<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Ezequiel Leonardo Castaño Personal Website</title><link href="https://elc.github.io/" rel="alternate"></link><link href="http://feeds.feedburner.com/feeds/all.atom.xml" rel="self"></link><id>https://elc.github.io/</id><updated>2023-09-23T00:00:00-03:00</updated><subtitle>Ezequiel Leonardo Castaño Personal Website - In this website you will find post about christianity, programming and math</subtitle><entry><title>Type-Safe Pipelines and Compose</title><link href="https://elc.github.io/posts/typed-pipes" rel="alternate"></link><published>2023-09-23T00:00:00-03:00</published><updated>2023-09-23T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2023-09-23:/posts/typed-pipes</id><summary type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/type_pipes_headerimage.png"&gt;&lt;img alt="Typed Pipes in Python" class="b-lazy" data-src="/blog/images/typed-pipes/type_pipes_headerimage.png" src="https://elc.github.io/blog/images/typed-pipes/type_pipes_headerimage-thumbnail.png" width="1683"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;When dealing with multiple transformations that run sequentially, one could
leverage the compose function to create pipelines. This article shows different
way to implement them in a type-safe way. All the code was written using pure
Python 3.11 and MyPy 1.5.1 and PyLance v2023.9.20&lt;/p&gt;


&lt;h2 id="function-composition"&gt;&lt;a class="toclink" href="#function-composition"&gt;Function …&lt;/a&gt;&lt;/h2&gt;</summary><content type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/type_pipes_headerimage.png"&gt;&lt;img alt="Typed Pipes in Python" class="b-lazy" data-src="/blog/images/typed-pipes/type_pipes_headerimage.png" src="https://elc.github.io/blog/images/typed-pipes/type_pipes_headerimage-thumbnail.png" width="1683"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;When dealing with multiple transformations that run sequentially, one could
leverage the compose function to create pipelines. This article shows different
way to implement them in a type-safe way. All the code was written using pure
Python 3.11 and MyPy 1.5.1 and PyLance v2023.9.20&lt;/p&gt;


&lt;h2 id="function-composition"&gt;&lt;a class="toclink" href="#function-composition"&gt;Function Composition&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are two notations for function composition one with a right-to-left
direction and one with a left-to-right direction. Namely:&lt;/p&gt;
&lt;p&gt;Right to left:&lt;/p&gt;
&lt;div class="math"&gt;$$f∘g = f(g(x))$$&lt;/div&gt;
&lt;p&gt;Left to right:&lt;/p&gt;
&lt;div class="math"&gt;$$f∘g = g(f(x))$$&lt;/div&gt;
&lt;p&gt;The traditional notation in math is the right-to-left one. Some languages like
Haskell has built-in syntax for both. In Haskell the usual way to do composition
is with &lt;code&gt;.&lt;/code&gt; which is right-to-left, it is also possible to use &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; for
left-to-right composition. &lt;/p&gt;
&lt;p&gt;On the other hand, one of the most common ways to compose functions in
programming is through Unix Pipes which use the &lt;code&gt;|&lt;/code&gt; operator, which conversely
is left-to-right composition.&lt;/p&gt;
&lt;p&gt;That means that when implementing a &lt;code&gt;compose&lt;/code&gt; or a &lt;code&gt;pipe&lt;/code&gt; function is not
trivial which orientation to choose as they are competing notations. In the
context of programming the left to right orientation is more common.&lt;/p&gt;
&lt;p&gt;All the examples here will use the left-to-right orientation.&lt;/p&gt;
&lt;h2 id="the-compose-function"&gt;&lt;a class="toclink" href="#the-compose-function"&gt;The compose function&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The compose function is a function that takes two functions &lt;code&gt;f&lt;/code&gt; and &lt;code&gt;g&lt;/code&gt; and
returns a new function that performs &lt;code&gt;g&lt;/code&gt; and then &lt;code&gt;f&lt;/code&gt;. In Python, a generic
implementation looks like this:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For this to work, it is necessary that the output of &lt;code&gt;f&lt;/code&gt; matches the input of
&lt;code&gt;g&lt;/code&gt;, or otherwise the execution may fail. To enforce this relationship a typed
version of the composed can be written as follows:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParamSpec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;T&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;U&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;U&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;P&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ParamSpec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;P&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;inner&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This implementation uses Python 3.10's &lt;code&gt;ParamSpec&lt;/code&gt;, which allows typing &lt;code&gt;*args&lt;/code&gt;
and &lt;code&gt;**kwargs&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Having a typed version is important as one typical case is composing multiple
functions and if the types are not enforced, unexpected behavior could arise.&lt;/p&gt;
&lt;p&gt;One example of using this compose implementation is the following:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;composed_functions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When using the typed version, both MyPy and Pyright can infer the resulting type:&lt;/p&gt;
&lt;p&gt;Pyright (through Pylance)&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/compose_pylance.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/compose_pylance.png" src="https://elc.github.io/blog/images/typed-pipes/compose_pylance-thumbnail.png" width="870"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MyPy&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/compose_mypy.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/compose_mypy.png" src="https://elc.github.io/blog/images/typed-pipes/compose_mypy-thumbnail.png" width="1070"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;One important aspect of function composition is that it is not commutative, that
is &lt;/p&gt;
&lt;div class="math"&gt;$$f∘g \neq g∘f$$&lt;/div&gt;
&lt;p&gt;. There may be cases where both are equivalent but most of
the time it is not.&lt;/p&gt;
&lt;p&gt;This is helpful when programming as the IDE can automatically detect and flag
types' incompatibility. Take for example trying to &lt;code&gt;add_one&lt;/code&gt; to the result of
&lt;code&gt;convert_to_string&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;composed_incorrect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pyright (through Pylance)&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/compose_pylance_error.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/compose_pylance_error.png" src="https://elc.github.io/blog/images/typed-pipes/compose_pylance_error-thumbnail.png" width="771"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MyPy&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/compose_mypy_error.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/compose_mypy_error.png" src="https://elc.github.io/blog/images/typed-pipes/compose_mypy_error-thumbnail.png" width="926"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The error from MyPy may not be descriptive enough but it at least points in the
right direction. Pyright can identify the exact cause of the problem:
&lt;code&gt;add_one&lt;/code&gt; takes an &lt;code&gt;int&lt;/code&gt; but it receives an &lt;code&gt;str&lt;/code&gt; as the output of
&lt;code&gt;convert_to_string&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="extension-to-multiple-functions"&gt;&lt;a class="toclink" href="#extension-to-multiple-functions"&gt;Extension to multiple functions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With that generic &lt;code&gt;compose&lt;/code&gt; function, it is possible to compose any number of
functions, however, the syntax is a little convoluted. These are the three
sample functions to compose, one is &lt;code&gt;int&lt;/code&gt; to &lt;code&gt;int&lt;/code&gt;, another one is &lt;code&gt;int&lt;/code&gt; to
&lt;code&gt;str&lt;/code&gt; and the last one is &lt;code&gt;str&lt;/code&gt; to &lt;code&gt;str&lt;/code&gt;, it is also interesting to use built-in
functions such as &lt;code&gt;len&lt;/code&gt; and &lt;code&gt;str&lt;/code&gt; instead of user-defined ones.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sort_characters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The composition of interest is the one that would be equivalent to doing:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;user_defined_composition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sort_characters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)))))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It is valid Python to create a function like that, but, it is difficult to read
and to change since the "application order" as well as the final "type mapping"
is hardcoded. Any variation would require a different signature and invocation
order.&lt;/p&gt;
&lt;p&gt;To leverage the generic &lt;code&gt;compose&lt;/code&gt;, one alternative would be to write:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;user_defined_composition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;sort_characters&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user_defined_composition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or equivalently:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;user_defined_composition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;sort_characters&lt;/span&gt;
            &lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nb"&gt;len&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user_defined_composition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: both approaches are valid and threw no errors when scanned with MyPy,
nevertheless, Pyright is not able to fully detect the types.&lt;/p&gt;
&lt;p&gt;Pyright:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/compose_test_pyright_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/compose_test_pyright_types.png" src="https://elc.github.io/blog/images/typed-pipes/compose_test_pyright_types-thumbnail.png" width="795"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/compose_test_pyright_problems.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/compose_test_pyright_problems.png" src="https://elc.github.io/blog/images/typed-pipes/compose_test_pyright_problems-thumbnail.png" width="1095"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MyPy:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/compose_test_mypy_type.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/compose_test_mypy_type.png" src="https://elc.github.io/blog/images/typed-pipes/compose_test_mypy_type-thumbnail.png" width="1072"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Neither of the previous is any easier to read than the original one. Some
languages do have a compact syntax for this use case. Haskell's &lt;code&gt;.&lt;/code&gt; is an
example of clear and concise syntax (Haskell has right to left application):&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;user_defined_composition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sort_characters&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;convert_to_string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This by no means implies that Python is not a good fit for composing functions,
it just lacks built-in syntax to make it more approachable. Even though the
previous example would work without issues, in the following sections easier and
more practical alternatives will be introduced.&lt;/p&gt;
&lt;h2 id="naive-iterative-pipe"&gt;&lt;a class="toclink" href="#naive-iterative-pipe"&gt;Naive Iterative Pipe&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The simplest evolution of &lt;code&gt;compose&lt;/code&gt; to multiple functions in a cleaner way would
be to wrap it in a for-loop:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pipe_iterative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;composed_function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;functions&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;composed_function&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;composed_function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;composed_function&lt;/span&gt;

&lt;span class="n"&gt;user_defined_composition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pipe_iterative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;sort_characters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user_defined_composition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This approach, albeit it will work, loses all the type information.&lt;/p&gt;
&lt;p&gt;Pyright:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_iterative_test_pyright_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/pipe_iterative_test_pyright_types.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_iterative_test_pyright_types-thumbnail.png" width="691"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MyPy:
&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_iterative_test_mypy_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/pipe_iterative_test_mypy_types.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_iterative_test_mypy_types-thumbnail.png" width="825"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;At the moment, it is not possible to type &lt;code&gt;*functions&lt;/code&gt; so that Python infers
that each of the functions will have an output type that will match the next
functions's input type.&lt;/p&gt;
&lt;p&gt;It is possible though to type the &lt;code&gt;pipe_iterative&lt;/code&gt; function if we assume that
all input and output types will be the same:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;T&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pipe_iterative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This signature is only applicable to a small subset of the possible function
compositions and will throw several errors with the functions used in the
previous examples.&lt;/p&gt;
&lt;p&gt;Pyright:&lt;/p&gt;
&lt;p&gt;In this case, the types are compatible with the &lt;code&gt;pipe_iterative&lt;/code&gt; signature but
are not what the function will expect.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_iterative_test_same_type_pyright_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/pipe_iterative_test_same_type_pyright_types.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_iterative_test_same_type_pyright_types-thumbnail.png" width="707"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_iterative_test_same_type_pyright_problems.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/pipe_iterative_test_same_type_pyright_problems.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_iterative_test_same_type_pyright_problems-thumbnail.png" width="938"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MyPy&lt;/p&gt;
&lt;p&gt;MyPy detects the conflicting types and assumes &lt;code&gt;Any&lt;/code&gt; will be the input and
output types.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_iterative_test_same_type_mypy_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/pipe_iterative_test_same_type_mypy_types.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_iterative_test_same_type_mypy_types-thumbnail.png" width="1074"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_iterative_test_same_type_mypy_problems.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/pipe_iterative_test_same_type_mypy_problems.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_iterative_test_same_type_mypy_problems-thumbnail.png" width="924"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Disagreeing two typing tools like this may be misleading and can cause issues
down the line. Pylance's error message is much more detailed and helpful in this
instance.&lt;/p&gt;
&lt;p&gt;If this type of composition is required though, there is a cleaner way of using
the &lt;code&gt;functools&lt;/code&gt; module.&lt;/p&gt;
&lt;h2 id="reduced-pipe"&gt;&lt;a class="toclink" href="#reduced-pipe"&gt;Reduced Pipe&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When a function takes an input type &lt;code&gt;T&lt;/code&gt;, returns the same type, and has one
identity element, it is said to be a &lt;em&gt;Monoid&lt;/em&gt;. It is a common word in the
Functional Programming jargon. The last signature of &lt;code&gt;pipe_iterative&lt;/code&gt; follows
this pattern since it always keeps its outputs and inputs within the type &lt;code&gt;T&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The definition of a &lt;em&gt;Monoid&lt;/em&gt; includes the identity element, since
pipes operate over functions, the identity element is a function that can be
composed without altering the result. This is trivially doable in Python:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;T&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There is a function that achieves the same and is built-in, the
&lt;code&gt;functools.reduce&lt;/code&gt;. The pipe function can then be rewritten as follows:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;reduce&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;functions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;user_defined_composition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;sort_characters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user_defined_composition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The same considerations could be made about the signature, this implementation
can either be type-safe and only operate on a single type &lt;code&gt;T&lt;/code&gt; or it could be
used more generically as the previous &lt;code&gt;pipe_iterative&lt;/code&gt; while losing type
information.&lt;/p&gt;
&lt;p&gt;Since the signature is the same, MyPy and Pyright show the same messages.&lt;/p&gt;
&lt;p&gt;There is a way to circumvent this issue and that is through the use of
&lt;code&gt;Generic&lt;/code&gt;s. Where types become an additional parameter. In Python, &lt;code&gt;Generic&lt;/code&gt;s
can only be used in classes, therefore the next sections will migrate to an
object-oriented programming style.&lt;/p&gt;
&lt;h2 id="why-types-matter"&gt;&lt;a class="toclink" href="#why-types-matter"&gt;Why Types matter&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If the previous is a working implementation, why bother with adding types? There
is a rising number of articles and online material arguing in favor of adding
types. A summary could be the following.&lt;/p&gt;
&lt;p&gt;Reasons to add types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Typed code produces fewer bugs&lt;/li&gt;
&lt;li&gt;Typed code enables enforcement of input and output compatibility &lt;/li&gt;
&lt;li&gt;Typed code can be checked statically, i.e. without running the code&lt;/li&gt;
&lt;li&gt;Typed code is easier to test comprehensively&lt;/li&gt;
&lt;li&gt;Typed code is easier to validate. See Pydantic for example&lt;/li&gt;
&lt;li&gt;Typed code is less ambiguous&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are also some reasons not to add types, namely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Types make the code more verbose&lt;/li&gt;
&lt;li&gt;Types make the learning curve for a codebase steeper&lt;/li&gt;
&lt;li&gt;&lt;strike&gt;Types are not supported in all versions&lt;/strike&gt;. All stable versions support types
  (3.8+).&lt;/li&gt;
&lt;li&gt;&lt;strike&gt;Some Type constructs, like ParamSpec are not available in old versions&lt;/strike&gt;.
  Use &lt;code&gt;typing_extensions&lt;/code&gt; if something is not supported&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And it is also important to clarify some myths&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Types will not make the code slower, they are ignored at runtime&lt;/li&gt;
&lt;li&gt;Types are not checked at runtime, they are just used by tools like IDEs and
  Linters&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="eager-monoidal-pipe"&gt;&lt;a class="toclink" href="#eager-monoidal-pipe"&gt;Eager Monoidal Pipe&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before diving too deep into different alternatives, the first step would be to
replicate what the previous &lt;code&gt;pipe&lt;/code&gt; function achieved but now supporting
different types.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;T&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;U&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;U&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PipeEagerSameType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;PipeEagerSameType&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="n"&gt;user_defined_composition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;PipeEagerSameType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sort_characters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user_defined_composition&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user_defined_composition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The implementation is straightforward, the class stores the initial value &lt;code&gt;x&lt;/code&gt;,
and then when &lt;code&gt;then&lt;/code&gt; is called, that value is transformed and saved. This method
returns &lt;code&gt;self&lt;/code&gt; to provide a 
&lt;a href="https://en.wikipedia.org/wiki/Fluent_interface" target="_blank"&gt;&lt;strong&gt;Fluent Interface&lt;/strong&gt;&lt;/a&gt;.
that makes the code easier to read. &lt;/p&gt;
&lt;p&gt;The result at the end could be obtained by either calling the instance and thus
executing &lt;code&gt;__call__&lt;/code&gt; or by simply accessing &lt;code&gt;x&lt;/code&gt;. The former approach makes the
instance behave like a function and the latter like a plain object.&lt;/p&gt;
&lt;p&gt;This first implementation using object-oriented programming produces similar yet
different messages from both Pyright and MyPy:&lt;/p&gt;
&lt;p&gt;Pyright:&lt;/p&gt;
&lt;p&gt;The errors are analogous to the implementation using &lt;code&gt;reduce&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_eager_same_type_pyright_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/pipe_eager_same_type_pyright_types.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_eager_same_type_pyright_types-thumbnail.png" width="793"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_eager_same_type_pyright_problems.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/pipe_eager_same_type_pyright_problems.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_eager_same_type_pyright_problems-thumbnail.png" width="679"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MyPy:&lt;/p&gt;
&lt;p&gt;This time the errors are much more descriptive and resemble those produced by
Pyright.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_eager_same_type_mypy_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/pipe_eager_same_type_mypy_types.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_eager_same_type_mypy_types-thumbnail.png" width="1064"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_eager_same_type_mypy_problems.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/pipe_eager_same_type_mypy_problems.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_eager_same_type_mypy_problems-thumbnail.png" width="1357"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now, whenever we inspect the type, both pyright and Mypy will output the class
name and the type will be encoded in the &lt;code&gt;Generic&lt;/code&gt;, i.e. the type now is
&lt;code&gt;PipeEagerSameType[int]&lt;/code&gt; and it is the &lt;code&gt;[int]&lt;/code&gt; part which tells the actual type.
In this case, it is the final return type which is inaccurate because the
assumption that all functions return the same type and the first one returns
&lt;code&gt;int&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The next step would be to try to keep the same easy-to-read syntax while at the
same time being able to pass functions with different signatures.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Eager&lt;/code&gt; in the class name is no coincidence, the previous examples using
&lt;code&gt;compose&lt;/code&gt; were not eagerly evaluated, they had a lazy evaluation strategy. This
implementation though transforms the value at each step. In the case of lazy
evaluation, all the transformations are defined first and evaluated only at the
end. Lazy implementations for this Pipe class will be introduced later on.&lt;/p&gt;
&lt;h2 id="eager-multitype-pipe"&gt;&lt;a class="toclink" href="#eager-multitype-pipe"&gt;Eager Multitype Pipe&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Due to the way &lt;code&gt;Generic&lt;/code&gt;s work, each instance can only hold a reference to a
single type &lt;code&gt;T&lt;/code&gt;. To support multiple types there are two possible solutions,
either use as many &lt;code&gt;TypeVar&lt;/code&gt;s as types needed or use as many instances as types
needed. The latter is more straightforward. The implementation looks like the
following:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;T&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;U&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;U&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PipeEager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;PipeEager&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PipeEager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;

&lt;span class="n"&gt;user_defined_composition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;PipeEager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sort_characters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user_defined_composition&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user_defined_composition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This time, instead of returning &lt;code&gt;self&lt;/code&gt;, a new instance is created, with the
updated value. Each instance now has information on the current step (through
&lt;code&gt;T&lt;/code&gt;), and the following step (through &lt;code&gt;U&lt;/code&gt;). The following step is not defined at
instantiation and therefore it is not needed to add &lt;code&gt;U&lt;/code&gt; to the &lt;code&gt;Generic&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;From the outside, the API is preserved, with the additional support for
functions with different types.&lt;/p&gt;
&lt;p&gt;Both Pyright and MyPy reflect types are properly inferred:&lt;/p&gt;
&lt;p&gt;Pyright:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_eager_pyright_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/pipe_eager_pyright_types.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_eager_pyright_types-thumbnail.png" width="858"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MyPy:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_eager_mypy_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/pipe_eager_mypy_types.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_eager_mypy_types-thumbnail.png" width="1019"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now, with a compatible implementation, the type has become &lt;code&gt;PipeEager[str]&lt;/code&gt;,
correctly inferring that calling the instance will return a &lt;code&gt;str&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;The next step is to make a Lazy implementation resemble the first ones built
with &lt;code&gt;compose&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="lazy-pipe-with-start"&gt;&lt;a class="toclink" href="#lazy-pipe-with-start"&gt;Lazy Pipe with Start&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To make a lazy implementation, the value should not be stored and
transformed, it will be provided last. Therefore what needs to be stored and
mapped are the transformations.&lt;/p&gt;
&lt;p&gt;To achieve this, a similar approach to the Eager classes can be used, but
replacing the value &lt;code&gt;x&lt;/code&gt; with a function &lt;code&gt;f&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParamSpec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;T&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;U&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;U&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;P&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ParamSpec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;P&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PipeLazyWithStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;PipeLazyWithStart&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PipeLazyWithStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;user_defined_composition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;PipeLazyWithStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sort_characters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user_defined_composition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case, rather than applying a transformation to the value and storing the
transformed result, an instance is created with a new transformation which is
the current and the next one composed. This allows the creation of new instances
each composing on the previous ones.&lt;/p&gt;
&lt;p&gt;The API is kept somewhat similar, it now resembles the approach with
&lt;code&gt;pipe_iterative&lt;/code&gt;, where all the functions are passed first and then evaluated on
a particular value.&lt;/p&gt;
&lt;p&gt;Pyright:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_lazy_with_start_pyright_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/pipe_lazy_with_start_pyright_types.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_lazy_with_start_pyright_types-thumbnail.png" width="1143"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MyPy:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_lazy_with_start_mypy_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/pipe_lazy_with_start_mypy_types.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_lazy_with_start_mypy_types-thumbnail.png" width="1445"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;With the lazy implementation, the types have changed slightly, now the type is
&lt;code&gt;PipeLazyWithStart[(x: int), str]&lt;/code&gt;, which means that it takes a single parameter
called &lt;code&gt;x&lt;/code&gt; of type &lt;code&gt;int&lt;/code&gt; and returns a single value of type &lt;code&gt;str&lt;/code&gt;. The &lt;code&gt;x&lt;/code&gt; name
comes from the instance variable with the same name in the class.&lt;/p&gt;
&lt;p&gt;In case the advantages of lazy evaluation are unclear, one of the following
sections will explain the pros and cons succinctly.&lt;/p&gt;
&lt;p&gt;The next step would be to simplify the class so that it can be instantiated
without an initial function, this could be helpful for many reasons, one example
is testing.&lt;/p&gt;
&lt;h2 id="lazy-pipe"&gt;&lt;a class="toclink" href="#lazy-pipe"&gt;Lazy Pipe&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To remove the initial function, the first impression would be to mark &lt;code&gt;f&lt;/code&gt; as
&lt;code&gt;Optional&lt;/code&gt;, however,  has lots of caveats, and MyPy and Pyright will complain. A
simple alternative is to create a helper class that surrogates the initial
creation of the LazyPipeline.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParamSpec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;T&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;P&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ParamSpec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;P&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PipeLazy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;PipeLazyWithStart&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;PipeLazyWithStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;user_defined_composition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;PipeLazy&lt;/span&gt;&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;convert_to_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sort_characters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user_defined_composition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This modification makes the implementation easily generalizable, being able to
pass yet uninstantiated pipelines down the line. It also forces the user to
specify the first input and output types of a given pipeline rather than
infering it which could help prevent bugs as things are more explicit now.&lt;/p&gt;
&lt;p&gt;Pyright:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_lazy_pyright_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/pipe_lazy_pyright_types.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_lazy_pyright_types-thumbnail.png" width="1095"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MyPy:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/pipe_lazy_mypy_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/pipe_lazy_mypy_types.png" src="https://elc.github.io/blog/images/typed-pipes/pipe_lazy_mypy_types-thumbnail.png" width="1398"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now the type is identical to the previous one but without specifying the &lt;code&gt;x&lt;/code&gt;,
that is because, at the moment of instantiation, the &lt;code&gt;PipeLazy&lt;/code&gt; object takes no
arguments. And even after being initialized with &lt;code&gt;[[int], int]&lt;/code&gt; it accurately
updated the return type to &lt;code&gt;str&lt;/code&gt; by following the chain of compositions.&lt;/p&gt;
&lt;p&gt;So far this implementation checks all the boxes, however, there is yet another
way to implement similar behavior leveraging less common Python features. The
next section will evolve this implementation to add support for decorators and
operator overloading.&lt;/p&gt;
&lt;h2 id="composable-objects"&gt;&lt;a class="toclink" href="#composable-objects"&gt;Composable Objects&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This section is kept to showcase some of the features of the language, but it
may result in code that is harder to read.&lt;/p&gt;
&lt;p&gt;Classes as decorators is an intermediate-advanced concept in Python, in fact,
&lt;code&gt;PipeLazyWithStart&lt;/code&gt; can already be used as a decorator since it only takes &lt;code&gt;f&lt;/code&gt;
which is a function.&lt;/p&gt;
&lt;p&gt;The other feature of the language that can be used is operator overloading, in
this case, the &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; operator (also known as right shift) which resembles the
&lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt; in Haskell for left-to-right composition. Other valid alternatives could
have been the &lt;code&gt;|&lt;/code&gt; or the &lt;code&gt;&amp;amp;&lt;/code&gt; (bitwise or and bitwise and respectively). Python
does not support the definition of custom operators so having a new &lt;code&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;
operator is not feasible.&lt;/p&gt;
&lt;p&gt;To overload the &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; operator one needs to define a &lt;code&gt;__rshift__&lt;/code&gt; method, which
in this case will have the same functionality as the &lt;code&gt;then&lt;/code&gt; method. The only
difference would be that it would need to handle functions and objects of the
same class.&lt;/p&gt;
&lt;p&gt;The implementation looks like the following:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParamSpec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;T&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;U&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;U&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;P&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ParamSpec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;P&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Q&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ParamSpec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Q&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Composable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Generic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__rshift__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Composable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;U&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Composable&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;other&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Composable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Composable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert_to_string_decorated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;user_defined_composition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Composable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;convert_to_string_decorated&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Composable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sort_characters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;
    &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;user_defined_composition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The resulting syntax with &lt;code&gt;&amp;gt;&amp;gt;&lt;/code&gt; is something &lt;em&gt;new&lt;/em&gt;, in some cases, like when
building a framework or an SDK, introducing new syntax like this could have
great benefit. One project that does this is Apache Airflow. However, most often
it results in niche uses that, without proper documentation could make the code
harder to read and maintain.&lt;/p&gt;
&lt;p&gt;Pyright:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/composable_pyright_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/composable_pyright_types.png" src="https://elc.github.io/blog/images/typed-pipes/composable_pyright_types-thumbnail.png" width="1033"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;MyPy:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/composable_mypy_types.png"&gt;&lt;img alt="Alt Text" class="b-lazy" data-src="/blog/images/typed-pipes/composable_mypy_types.png" src="https://elc.github.io/blog/images/typed-pipes/composable_mypy_types-thumbnail.png" width="1174"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/typed-pipes/composable_mypy_problems.png"&gt;&lt;img alt="Alt Text" class="b-lazy narrow" data-src="/blog/images/typed-pipes/composable_mypy_problems.png" src="https://elc.github.io/blog/images/typed-pipes/composable_mypy_problems-thumbnail.png" width="787"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The types are identical to those of &lt;code&gt;PipeLazyWithStart&lt;/code&gt;, however, Mypy complains
about not being able to infer the type of the first parameter of &lt;code&gt;compose&lt;/code&gt;,
which is unexpected. This may have been due to the interaction between
&lt;code&gt;ParamSpec&lt;/code&gt;s and &lt;code&gt;TypeVars&lt;/code&gt; in an edge case.&lt;/p&gt;
&lt;h2 id="why-does-lazy-evaluation-matter"&gt;&lt;a class="toclink" href="#why-does-lazy-evaluation-matter"&gt;Why does Lazy Evaluation matter?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Eager vs. Lazy evaluation is a topic that would deserve an article on its own.
There are tools like &lt;code&gt;polars&lt;/code&gt; and &lt;code&gt;pandas&lt;/code&gt; that use eager evaluation and at the
same time other tools like &lt;code&gt;pyspark&lt;/code&gt; use lazy evaluation.&lt;/p&gt;
&lt;p&gt;The following are some key questions to help decide which is better for each
case:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Speed - Either&lt;/li&gt;
&lt;li&gt;Easy to read code - Either&lt;/li&gt;
&lt;li&gt;Easy to test code - Either&lt;/li&gt;
&lt;li&gt;Easy to debug code / interactive programming - Eager&lt;/li&gt;
&lt;li&gt;Optimized transformations - Lazy&lt;/li&gt;
&lt;li&gt;Flexibility - Lazy&lt;/li&gt;
&lt;li&gt;Separation of transformations from data - Lazy&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are scenarios where certain operations need to be applied sequentially,
that is a hint for the pipeline pattern which can be implemented with either an
Eager or a Lazy evaluation approach.&lt;/p&gt;
&lt;p&gt;Knowing when to use which depends on the scenario but the key aspect is to
structure the code so that the final result is easy to read, easy to test and
easy to maintain.&lt;/p&gt;
&lt;p&gt;On a personal note, I believe that unless required, the LazyPipe would suffice
most of the time, and in case it doesn't switching to the Eager version is a
minor change that should not introduce any breaks down the line.&lt;/p&gt;
&lt;p&gt;If dealing with a lot of error handling, these pipelines could be combined with
Railway Oriented Programming to streamline processes end to end.&lt;/p&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (true) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML';
    mathjaxscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'AMS' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="Programming"></category><category term="Python"></category><category term="Types"></category><category term="Pipelines"></category></entry><entry><title>ANGEL - An Oppinionated Guide on how to Learn Programming (focusing on Python)</title><link href="https://elc.github.io/posts/angel" rel="alternate"></link><published>2023-07-30T00:00:00-03:00</published><updated>2023-07-30T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2023-07-30:/posts/angel</id><summary type="html">&lt;p&gt;&lt;a href="/blog/images/angel-guide/angel-guide-headerimage.png"&gt;&lt;img alt="Article Header Image" class="b-lazy" data-src="/blog/images/angel-guide/angel-guide-headerimage.png" src="https://elc.github.io/blog/images/angel-guide/angel-guide-headerimage-thumbnail.png" width="1280"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Courses and pieces of training claiming to deliver rapid results have become
increasingly popular these days. Nonetheless, amidst the abundance of online
resources, it can be challenging to distinguish valuable ones from the noise.
Enter &lt;strong&gt;ANGEL&lt;/strong&gt;, which stands for "ANGEL's Not a Guide to Effortlessly Learning."
This guide presents readers …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="/blog/images/angel-guide/angel-guide-headerimage.png"&gt;&lt;img alt="Article Header Image" class="b-lazy" data-src="/blog/images/angel-guide/angel-guide-headerimage.png" src="https://elc.github.io/blog/images/angel-guide/angel-guide-headerimage-thumbnail.png" width="1280"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Courses and pieces of training claiming to deliver rapid results have become
increasingly popular these days. Nonetheless, amidst the abundance of online
resources, it can be challenging to distinguish valuable ones from the noise.
Enter &lt;strong&gt;ANGEL&lt;/strong&gt;, which stands for "ANGEL's Not a Guide to Effortlessly Learning."
This guide presents readers with a practical approach to the programming
learning experience. While the examples will be specific to Python, the reader
can apply the core content to any programming language or framework.&lt;/p&gt;


&lt;p&gt;Indeed, writing with both potential readers in mind is essential to ensure that
the content resonates with learners and teachers alike. In this article, we'll
address "the learner" as the protagonist in a more impersonal manner. Whenever
"the learner" is mentioned, it refers to YOU if you are someone eager to learn,
and if you are a teacher, "the learner" represents YOUR learners. By striking
this balance, we can provide valuable insights and guidance to everyone involved
in the learning process.&lt;/p&gt;
&lt;p&gt;Programming is not an innate ability but rather a skill that requires deliberate
development. Although not impossible to learn, it may not be &lt;a href="https://www.youtube.com/watch?v=EFwa5Owp0-k" target="_blank"&gt;necessary or
suitable for everyone&lt;/a&gt;. This guide
takes a meta-analysis approach from an "angel's" point of view (pun intended).
Rather than providing a rigid set of precise resources or a specific order of
topics, this guide concentrates on the learning journey. It offers valuable
insights and tips to help learners avoid frustration, maintain engagement, and
establish a clear framework for progression.&lt;/p&gt;
&lt;p&gt;Some key ideas should be taken into consideration while reading:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ownership&lt;/strong&gt;: The learning process belongs to the learner. No one can guide
  them better in "learning to learn" than themselves. While teachers and mentors
  are valuable sources of support and guidance, the learner must take charge of
  discovering how they learn best, being actively involved and interested in
  shaping their learning process to make it more effective and enjoyable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Overshooting and Undershooting&lt;/strong&gt;:  drawing from control theory, in practical
  terms, it means that being too strict or too lax in one's approach can hinder
  progress. While understanding the advantages and disadvantages of different
  method is vital, excessively deviating from a structured approach may lead to
  confusion and challenges. The learner should be open to exploring new things
  in a controlled and measured way while avoiding chaos.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Same Destination&lt;/strong&gt;: when following a roadmap to learn something, it's
  crucial to recognize that not everyone will take the same path. Diversity in
  learning styles and methods is natural and should be embraced. Each learner's
  unique approach doesn't necessarily indicate superiority or inferiority in
  learning ability. With enough time and dedication, everyone can achieve a
  comparable level of proficiency, although individual objectives may lead to
  slightly different outcomes. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The sections in this article are thoughtfully structured as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Learner Profiles&lt;/strong&gt;: This section provides background information about the
  learners, including their previous experiences and personal goals related to
  programming.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learning Approaches&lt;/strong&gt;: Here, the post explores how the content is structured
  and organized, potentially outlining different learning paths or
  methodologies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Thinking Style&lt;/strong&gt;: This section delves into how learners process information
  and generate insights, which can impact their learning experience.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learning Material&lt;/strong&gt;: Considerations for selecting appropriate learning
  materials. The quality and relevance of the resources chosen can significantly
  impact the learning journey.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Roadmap&lt;/strong&gt;: This roadmap serves as a clear path to follow, highlighting
  stages for learners to progress steadily in their programming competence.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Closing Thoughts&lt;/strong&gt;:  It wraps up the guide, giving learners a sense of
  direction and motivation to continue their learning journey.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;SPOILER ALERT&lt;/strong&gt;: It's essential to note that this guide isn't a quick and
superficial "Learn X in Y minutes" type of resource. There are no TL;DR,
summaries, or skippable sections. This post is thought for those genuinely
invested and wanting to thoroughly read and absorb the content. &lt;/p&gt;
&lt;h2 id="learner-profiles"&gt;&lt;a class="toclink" href="#learner-profiles"&gt;Learner Profiles&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Individuals embark on learning programming for various reasons and bring diverse
backgrounds to the table. Acknowledging these differences and adjusting
expectations is vital to create a roadmap that facilitates effective knowledge
acquisition.&lt;/p&gt;
&lt;p&gt;Below, some typical learner stereotypes will be examined. While it's crucial to
recognize that these stereotypes are not entirely accurate and may not encompass
the full breadth of learner profiles, they provide a fair simplification that
allows for better planning and organization.&lt;/p&gt;
&lt;h2 id="other-field-professional"&gt;&lt;a class="toclink" href="#other-field-professional"&gt;Other Field Professional&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Learners from diverse fields like finance, biology, marketing, or any non-IT
domain, often seek to learn programming, particularly Python, to enhance their
skill sets. Their motivation stems from specific goals, such as automating
repetitive tasks, conducting data analysis, or developing applications relevant
to their respective domains. While they might not prioritize high-quality code,
their main objective is to achieve efficient and effective solutions that get
the job done.&lt;/p&gt;
&lt;p&gt;For instance, individuals with a background in the stock market may be
interested in learning Python for algorithmic trading, as highlighted in this
&lt;a href="https://www.youtube.com/watch?v=xfzGZB4HhEE" target="_blank"&gt;FreeCodeCamp Course with 2M
views&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;These learners typically possess expertise in their respective fields but may
have limited or no programming background. They are focused on achieving
tangible results and may prioritize functionality over writing high-quality
code. &lt;a href="https://www.youtube.com/user/PyDataTV" target="_blank"&gt;PyData Conferences&lt;/a&gt;  are a
testament to the widespread adoption of Python among learners  from non-IT
fields, where many professionals showcase how they employ Python as an effective
tool in their daily work.&lt;/p&gt;
&lt;h2 id="tinkerers"&gt;&lt;a class="toclink" href="#tinkerers"&gt;Tinkerers&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Python has a magnetic appeal for learners who have a tinkering spirit and love
to experiment with code. These learners are naturally curious and enjoy the
process of experimenting with code, embarking on personal projects, creating
utilities, and exploring Python's vast potential for creative expression.&lt;/p&gt;
&lt;p&gt;A prime example of this kind of learner is someone who aims to learn Python to
automate tasks in their home using Raspberry Pi and delve into the world of
domotics, as showcased in the &lt;a href="https://www.youtube.com/playlist?list=PLQVvvaa0QuDesV8WWHLLXW_avmTzHmJLv" target="_blank"&gt;Sentdex Guide with 500K
views&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;While they are keen on understanding what they are doing, they might not
necessarily delve deeply into the theoretical aspects of programming. Instead,
the focus lies on testing multiple solutions and optimizing for performance.
They prefer practical and tangible outcomes rather than diving into the
intricacies of the underlying algorithms.&lt;/p&gt;
&lt;h2 id="career-switchers-leverage-seeker"&gt;&lt;a class="toclink" href="#career-switchers-leverage-seeker"&gt;Career Switchers / Leverage Seeker&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;These learners want to transition to a new career as their primary goal, often
utilizing programming as leverage to achieve this change. They may or may not
have a background in programming but are especially interested in maximizing
returns with minimal effort.&lt;/p&gt;
&lt;p&gt;An example could be someone feeling locked into their current job or career
path. They are not entirely comfortable with their daily job and seek an exit
strategy. As a result, they are often looking for efficient and rapid ways to
acquire the necessary programming skills that can open new opportunities. As
this &lt;a href="https://www.youtube.com/watch?v=rfscVS0vtbw" target="_blank"&gt;FreeCodeCamp Course with 40M
views&lt;/a&gt;  shows&lt;/p&gt;
&lt;p&gt;A typical subtype within this category is the high school or college student who
solely wants to learn what is needed to pass an exam or fulfill specific
academic requirements. Their focus is on attaining the necessary skills to
achieve academic success.&lt;/p&gt;
&lt;h2 id="theorists-scholars"&gt;&lt;a class="toclink" href="#theorists-scholars"&gt;Theorists / Scholars&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Theorists and scholars, often coming from a Computer Science or related
background, approach learning Python with a specific purpose – to implement
algorithms and data structures with a strong emphasis on code analysis,
particularly time and space complexity.&lt;/p&gt;
&lt;p&gt;A classic example of this type of learner is a college student attending an
Algorithms and Data Structures class or someone involved in research within this
field. For instance, this &lt;a href="https://www.youtube.com/playlist?list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb" target="_blank"&gt;MIT Course with 5M
views&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;Theorists and scholars typically have a narrow perspective on code, emphasizing
performance, correctness, and theoretical analysis. They are less concerned with
"idiomatic" or conventional coding practices and may not prioritize aspects
related to software project management. Instead, they focus on maximizing the
efficiency and effectiveness of individual pieces of code.&lt;/p&gt;
&lt;h2 id="professional-developer"&gt;&lt;a class="toclink" href="#professional-developer"&gt;Professional Developer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Professional developers who work with Python or other programming languages
bring a wealth of experience and software development knowledge to the table.
For them, Python is another valuable tool in their arsenal that can be
beneficial in specific scenarios and alongside other languages.&lt;/p&gt;
&lt;p&gt;An exemplary case of this type of learner is someone who has already learned
Python but is now looking to deepen their understanding of design patterns to
enhance the robustness of their code. As this &lt;a href="https://www.youtube.com/playlist?list=PLC0nd42SBTaNuP4iB4L6SJlMaHE71FG6N" target="_blank"&gt;Arjan's Software Design Playlist
with 250K views
shows&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;These learners often come with a set of pre-existing skills and practices from
their background in software development. As a result, they might not fully
embrace Python's "way of doing things," but they are dedicated to maintaining
high-quality code and adopting a product-oriented approach.&lt;/p&gt;
&lt;h2 id="learning-approaches"&gt;&lt;a class="toclink" href="#learning-approaches"&gt;Learning approaches&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Learning approaches can vary widely across available resources, and not all
styles may be suitable for every learner, regardless of their profile. In this
section, we'll explore three of the most typical learning approaches:&lt;/p&gt;
&lt;h2 id="bottom-up"&gt;&lt;a class="toclink" href="#bottom-up"&gt;Bottom-Up&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Bottom-Up learning strategy is characterized by starting from foundational
concepts and gradually building upon them to understand more complex ideas. This
approach breaks down concepts into smaller, easy-to-digest pieces, emphasizing a
solid foundation before tackling more advanced topics.&lt;/p&gt;
&lt;h3 id="pros"&gt;&lt;a class="toclink" href="#pros"&gt;Pros&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Solid Foundation&lt;/strong&gt;: Learners gain a reliable and solid foundation in
  programming. By understanding the smaller building blocks, they can construct
  more significant and complex solutions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Easy-to-Digest&lt;/strong&gt;: Focusing on manageable and easy-to-understand bits ensures
  learners grasp the fundamentals thoroughly, preventing information overload.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Progressive Learning&lt;/strong&gt;: New knowledge is built upon previously taught
  material, creating a sense of continuity and progression in the learning
  journey.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cons"&gt;&lt;a class="toclink" href="#cons"&gt;Cons&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Time to Tangible Results&lt;/strong&gt;: The emphasis on learning basics and building
  blocks may delay seeing tangible results or practical applications, leading to
  frustration or an unproductive sensation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Impostor Syndrome&lt;/strong&gt;: Learners may develop &lt;a href="https://en.wikipedia.org/wiki/Impostor_syndrome" target="_blank"&gt;impostor
  syndrome&lt;/a&gt;
  , feeling that they only know the building blocks and haven't built anything
  substantial, underestimating their capabilities.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fragmented Knowledge&lt;/strong&gt;: The focus on independent parts can hinder learners
  from seeing the big picture and understanding how different concepts relate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Start from Scratch&lt;/strong&gt;: This approach often involves starting from scratch,
  which may not align with real-world scenarios where learners might work with
  existing codebases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Long-Term Retention&lt;/strong&gt;: As learners progress through individual components,
  their knowledge can become fragmented and hinder long-term retention if not
  periodically reviewed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="example"&gt;&lt;a class="toclink" href="#example"&gt;Example&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Most guides, tutorials, and even university courses often follow the bottom-up
learning approach. They start by teaching foundational concepts such as
variables, control structures, and data structures, and then progressively move
to solving larger problems by reusing the previously taught concepts.&lt;/p&gt;
&lt;p&gt;Proponents would say "You cannot start with X unless you cover W, Y, and Z in
detail first."&lt;/p&gt;
&lt;p&gt;Detractor would say one may be "Missing the forest for the trees".&lt;/p&gt;
&lt;h2 id="top-down"&gt;&lt;a class="toclink" href="#top-down"&gt;Top-Down&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The top-down learning approach focuses on starting with the "big picture" and
making something work even if the learner doesn't fully understand all the
underlying details. From there, they build on the working solution and delve
into the specifics.&lt;/p&gt;
&lt;h3 id="pros_1"&gt;&lt;a class="toclink" href="#pros_1"&gt;Pros&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Avoiding Excessive Frustration&lt;/strong&gt;: it helps avoid excessive frustration as
  learners start with a known solution, reducing trivial errors like syntax
  mistakes or wrong operators.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fast Working Solution&lt;/strong&gt;: Learners can achieve a functional result relatively
  quickly, gaining a sense of accomplishment early on.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Project-Based Approach&lt;/strong&gt;: The top-down approach naturally adopts a
  project-based learning style, resonating well with many learners who prefer
  practical, hands-on experiences.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database of Examples&lt;/strong&gt;: By starting with working solutions, learners build a
  database of examples that can be leveraged in future projects, reducing the
  need for extensive long-term recall.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cons_1"&gt;&lt;a class="toclink" href="#cons_1"&gt;Cons&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://www.youtube.com/watch?v=kcfRe15I47I" target="_blank"&gt;Dunning-Krugger 
  Effect&lt;/a&gt;&lt;/strong&gt;: 
  Learners may be susceptible to overestimating their
  competence, believing they understand more than they do, leading to a false
  sense of mastery.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Difficulty in Troubleshooting&lt;/strong&gt;: When faced with errors or issues, learners
  may struggle to troubleshoot effectively, lacking the foundational knowledge
  to explore the reasons behind them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Starting from Scratch&lt;/strong&gt;: Learners might experience challenges when starting
  a project from scratch, as they have accustomed to pre-filled boilerplate code
  during the initial phase.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Oversimplification of Concepts&lt;/strong&gt;: In some cases, concepts may be
  oversimplified, hiding their true complexities. When learners deviate too
  much, they may encounter daunting intricacies.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="example_1"&gt;&lt;a class="toclink" href="#example_1"&gt;Example&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A prominent resource that follows the top-down approach is &lt;a href="https://course.fast.ai/" target="_blank"&gt;FastAI's Practical
Deep Learning for Coders&lt;/a&gt; . &lt;/p&gt;
&lt;p&gt;Proponents would say:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;X is not hard, you just need W, Y, Z.&lt;/li&gt;
&lt;li&gt;Don't worry if you don't understand now, it will become clearer later. &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Detractor would say one may be "Ignoring the devil in the details".&lt;/p&gt;
&lt;h2 id="experimental"&gt;&lt;a class="toclink" href="#experimental"&gt;Experimental&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The experimental learning approach is characterized by a trial-and-error
mindset. Learners focus on making a specific solution work without overly
concerning themselves with alternative approaches or how individual building
blocks interact.&lt;/p&gt;
&lt;h3 id="pros_2"&gt;&lt;a class="toclink" href="#pros_2"&gt;Pros&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Domain Expertise&lt;/strong&gt;: The experimental approach allows learners to explore
  multiple paths, creating domain-specific expertise in the process.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hands-On Learning&lt;/strong&gt;: Learners consolidate their knowledge through hands-on
  experience, gaining practical insights into problem-solving.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Avoiding Dunning-Kruger Effect&lt;/strong&gt;: By facing errors and challenges multiple
  times, learners avoid the Dunning-Kruger effect and develop a more realistic
  assessment of their skills.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Overcoming Impostor Syndrome&lt;/strong&gt;: Encountering both failures and successes
  reinforces learners' confidence, preventing impostor syndrome.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reinforcement and Faster Recall&lt;/strong&gt;: This approach strengthens learners'
  understanding of solutions for similar problems. They can recall how certain
  problems were solved more efficiently in the future.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cons_2"&gt;&lt;a class="toclink" href="#cons_2"&gt;Cons&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Time-Consuming&lt;/strong&gt;: The experimental approach can be time-consuming, as learners
  try out different approaches and solutions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Domain-Specific Knowledge&lt;/strong&gt;: The knowledge acquired through experimentation may
  be highly domain-specific and not easily applicable to other areas.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fragmented Knowledge&lt;/strong&gt;: Learners may end up with fragmented knowledge,
  understanding how pieces fit together for specific solutions but struggling to
  apply them in different contexts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bias Towards Past Solutions&lt;/strong&gt;: Having invested many hours in trying to solve a
  particular problem, learners might prematurely dismiss options that were
  previously discarded, limiting their exploration of alternative solutions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="example_2"&gt;&lt;a class="toclink" href="#example_2"&gt;Example&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One example of the experimental learning approach can be found in the YouTube
channel &lt;a href="https://www.youtube.com/@StuffMadeHere" target="_blank"&gt;"Stuff Made Here"&lt;/a&gt; .This channel
tackles novel problems where previous solutions are suboptimal, and the creator
explores multiple attempts to gain experience and refine the approach. This
channel effectively combines software and hardware aspects, making it a valuable
resource for hands-on learning.&lt;/p&gt;
&lt;p&gt;Another scenario where the experimental approach is commonly used is in
hackathons. Participants often explore different solutions and experiment with
various technologies to find the most suitable and innovative solutions within a
short timeframe.&lt;/p&gt;
&lt;p&gt;Proponents would say "You just need to sit down and focus on it until it works".&lt;/p&gt;
&lt;p&gt;Detractor would say one could be "A one-trick pony".&lt;/p&gt;
&lt;h2 id="thinking-style"&gt;&lt;a class="toclink" href="#thinking-style"&gt;Thinking Style&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Understanding the thinking style of learners is crucial in presenting
information in a way that resonates with them and enhances their learning
experience. People can be categorized into two main thinking styles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Analytic Thinkers&lt;/strong&gt;: These individuals prefer to break down complex
  information into smaller, more manageable details and subgroups. They excel at
  analyzing and dissecting concepts to understand their intricacies thoroughly.
  They often appreciate a bottom-up learning approach, where they start with
  foundational concepts and gradually build a comprehensive understanding.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Holistic Thinkers&lt;/strong&gt;: Holistic thinkers, on the other hand, find it easier to
  see the grand scheme of things at once. They prefer to see how various
  concepts are interconnected and how they create a cohesive structure. For
  holistic thinkers, a top-down learning approach, starting with an overview and
  then delving into specifics, may be more appealing.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, information organization preference can be categorized into two
styles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Hierarchical Thinkers&lt;/strong&gt;: Hierarchical thinkers prefer taxonomies and
  hierarchical structures to organize information. They find it natural to group
  concepts into categories, subcategories, and broader groups, similar to
  organizing files in a directory structure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Networked Thinkers&lt;/strong&gt;: Networked thinkers see concepts as independent ideas
  interconnected through relationships, much like social networks. They prefer
  to understand how various concepts relate to one another rather than
  organizing them hierarchically.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Authors and educators might naturally lean towards one thinking style or
information organization. The alignment between the author's presentation style
and the reader's thinking style can significantly impact how well the
information is understood and absorbed.&lt;/p&gt;
&lt;p&gt;If you're interested in exploring this topic further, the resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Opy-SjDU0UY" target="_blank"&gt;How culture made Japanese Internet design
  "Weird"&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://win.hyperquery.ai/p/notion-vs-roam-core-philosophies" target="_blank"&gt;Notion vs. Roam - core philosophies and the behaviors they
  enable&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="learning-material"&gt;&lt;a class="toclink" href="#learning-material"&gt;Learning Material&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is no one-size-fits-all approach, and diversity in learning resources can
be beneficial for learners. Different individuals may prefer various formats,
including videos, text-based materials, MOOCs (Massive Open Online Courses), 1:1
mentoring, interactive exercises, and more. Each format has its advantages and
appeals to different learning styles and preferences.&lt;/p&gt;
&lt;p&gt;The idea of a "visual learner" &lt;a href="https://www.youtube.com/watch?v=rhgwIhB58PA" target="_blank"&gt;has been
challenged&lt;/a&gt; , as the most effective
learning experiences often involve a combination of various approaches. The more
diverse the learning methods, the better learners can engage with the material
and enhance their understanding.&lt;/p&gt;
&lt;p&gt;Active participation is a crucial aspect of effective learning. Engaging
learners and making them actively participate in the learning process can
significantly improve knowledge retention and understanding. Gamification, a
technique that uses game elements and mechanics in a non-gaming context, is one
approach that teachers and educators can use to make learning more interactive,
enjoyable, and effective, especially when dealing with complex concepts.&lt;/p&gt;
&lt;h3 id="attention-spans"&gt;&lt;a class="toclink" href="#attention-spans"&gt;Attention Spans&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In today's fast-paced digital age, attention spans have been decreasing, and
there is a growing demand for short and easily digestible content, especially on
social networking sites. However, presenting complex information in such a brief
format can be challenging, as it may require oversimplifications or assume a
significant amount of prior knowledge.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://us.pycon.org/2023/schedule/tutorials/" target="_blank"&gt;Python tutorials at events like
PyCo&lt;/a&gt;  often last for more than 3
hours because they aim to provide hands-on and in-depth learning experiences.
Learning programming concepts and skills requires time and practice, and it
cannot be condensed into quick soundbites or short videos. Programming is a
skill that needs to be nurtured and honed through active engagement and
practical application.&lt;/p&gt;
&lt;h3 id="noise-to-signal-ratio"&gt;&lt;a class="toclink" href="#noise-to-signal-ratio"&gt;Noise to Signal Ratio&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With the vast amount of information available on the internet, distinguishing
between valuable and mediocre resources can be challenging, especially for
complete beginners. This concept essentially refers to the ratio between
high-quality, valuable resources (the signal) and less useful or irrelevant
information (the noise).&lt;/p&gt;
&lt;p&gt;For complete beginners, it's essential to exercise caution and be selective
about the sources they rely on for learning. Beginners may lack the experience
and knowledge to distinguish credible and accurate resources from those
containing errors or outdated information.&lt;/p&gt;
&lt;p&gt;When reviews are not available, learners can use proxy indicators to gauge a
resource's value:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How many people reviewed it positively? (e.g. at Coursera/Udemy/Pluralsight)&lt;/li&gt;
&lt;li&gt;How many people watch it? (e.g. on Youtube)&lt;/li&gt;
&lt;li&gt;How many people like it? (e.g. on Medium)&lt;/li&gt;
&lt;li&gt;Where was it published? (e.g. at a PyCon)&lt;/li&gt;
&lt;li&gt;Is this official documentation?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="recommendations"&gt;&lt;a class="toclink" href="#recommendations"&gt;Recommendations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Be wary of recommendations, as it is particularly tricky due to &lt;a href="https://www.youtube.com/watch?v=yCfMIZupyfE" target="_blank"&gt;expert
blindness&lt;/a&gt; . Expert blindness can
influence how experienced individuals perceive and recommend certain materials
or approaches. What works well for them at their current level of expertise
might not be the most suitable choice for beginners who lack that prior
knowledge.&lt;/p&gt;
&lt;p&gt;For example, recommending a fully-fledged IDE to a beginner might overwhelm them
with its complexity and hinder their learning process. While it might be an
invaluable tool for an experienced programmer, it might not be the best starting
point for someone just beginning their programming journey.&lt;/p&gt;
&lt;p&gt;Assessing which learning material, roadmap, or approach to use can be
subjective, and what works for one person might not work as effectively for
another. Learners should take experts' advice with a grain of salt.&lt;/p&gt;
&lt;p&gt;Learning Git is a classic example of the challenges with recommendations. Git is
a powerful version control system, and learning resources are numerous. What
might be a "game-changer" for one person might not be the best fit for someone
else. Beginners often benefit from exploring multiple resources and finding the
ones that resonate best with their learning style.&lt;/p&gt;
&lt;p&gt;"Aha!" moments can be transformative, but they can differ for each individual
due to their unique backgrounds and existing knowledge. Some learners might have
breakthroughs with a specific resource, while others might find that same
resource less helpful.&lt;/p&gt;
&lt;h2 id="self-identification"&gt;&lt;a class="toclink" href="#self-identification"&gt;Self Identification&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Understanding one's self-identification as a learner is crucial as it can guide
the choice of learning approaches and resources that best suit individual needs.
It's common for individuals to identify with one or more types of learners, and
these identifications may change over time as one gains more experience and
knowledge.&lt;/p&gt;
&lt;p&gt;For example, those who identify as "Tinkerers" may naturally gravitate towards
the "Experimental" approach, enjoying hands-on exploration and experimentation.
"Theorists" may lean towards the "Bottom-Up" approach, delving into the
theoretical aspects and code analysis. "Other Field Professionals" might prefer
the "Top-Down" approach, seeking to apply Python to their specific domains.
"Professional Developers" and "Career Switchers" might find benefit in various
approaches, depending on their specific interests and goals.&lt;/p&gt;
&lt;p&gt;This post is primarily oriented toward a combination of the "Theorist" and the
"Professional Developer" learner types. It is not a quick "Learn Python in X
days/months" guide for "Career Switchers," nor a "How to automate things with
Python" tutorial for "Tinkerers." However, depending on te learner's interests
and background, those identifying as an "Other Field Professional" may still
find valuable insights and benefits in this guide.&lt;/p&gt;
&lt;h3 id="working-in-a-team"&gt;&lt;a class="toclink" href="#working-in-a-team"&gt;Working in a Team&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Working in a team can yield the best results when there is a diverse mix of
profiles among team members. Assuming equal competence, having a combination of
analytical and holistic thinkers can enrich the team's experience more than if
everyone had the same thinking style.&lt;/p&gt;
&lt;p&gt;As one climbs higher in the organizational hierarchy, the need for a more
holistic approach becomes apparent. Higher-level positions require considering
problems in the context of features, products, portfolios, strategies, and
overall value and profit. C-Suite executives often work at the strategy level,
where specific feature details may be abstracted away.&lt;/p&gt;
&lt;p&gt;As organizations grow, this hierarchical nature becomes more pronounced. This
also explains the distinction between Individual Contributors (IC) and Managers.
Individual Contributors typically possess analytical thinking skills, capable of
handling complex tasks with a single-minded focus. In contrast, Managers tend to
be people-centric and adopt a holistic approach, keeping the big picture in mind
while managing details.&lt;/p&gt;
&lt;p&gt;Transitioning from an IC to a Manager role is not always a seamless process, and
not everyone may find it suitable for them. Some individuals might prefer to
remain in IC roles, as they excel in handling complexities and prefer focused
tasks. On the other hand, those who embrace a more holistic mindset and enjoy
managing teams and projects may thrive in managerial positions.&lt;/p&gt;
&lt;p&gt;Understanding these dynamics can help shape the career outlook for learners. By
recognizing their strengths and preferences, learners can make informed
decisions about the type of role and career path they want to pursue.&lt;/p&gt;
&lt;h2 id="the-roadmap"&gt;&lt;a class="toclink" href="#the-roadmap"&gt;The Roadmap&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The remainder of the article will explore an approach to learning from scratch
through different levels of competence. The idea is to divide the learning
process into different stages and give specific recommendations for each stage.
Before continuing, remember that &lt;a href="https://www.wikiwand.com/en/All_models_are_wrong" target="_blank"&gt;"All models are wrong, but some are
useful"&lt;/a&gt; &lt;/p&gt;
&lt;h2 id="knowledge-vs-competence"&gt;&lt;a class="toclink" href="#knowledge-vs-competence"&gt;Knowledge vs Competence&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The distinction between knowledge and competence is crucial when it comes to
learning programming. Learning materials typically focus on imparting knowledge,
which comprises information and facts about a specific topic. However, learners,
employers, and everyone involved ultimately seek competence, which refers to the
ability to apply that knowledge effectively in real-world situations.&lt;/p&gt;
&lt;p&gt;A challenge arises when evaluating competency, as there are limited tools
available for its assessment compared to the abundance of tools to test
knowledge. Job interviews, for instance, are often time-boxed, limiting the
depth of competency assessment. As a result, proxies such as quizzes, code
challenges, or design questions are commonly used. Evaluating soft skills is
also a valuable proxy, as they are essential for competence in certain roles,
such as effective communication for a skilled software architect. To read more
about this topic, have a look at &lt;a href="https://fagnerbrack.com/the-fate-metrics-for-hiring-98724fb0416" target="_blank"&gt;Fagner Brack's
article&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;Passing knowledge tests, such as exams, does not automatically imply competency.
Competency evaluation is a more time-consuming process that involves analyzing
an individual's strengths and weaknesses in practical situations. Due to its
complexity, it does not scale well for large groups of learners. As a result,
most teaching processes involving multiple learners primarily assess knowledge,
with some individuals developing competency to varying degrees.&lt;/p&gt;
&lt;p&gt;Mentorships stand out as an exception, as they focus on testing competency
rather than knowledge. A mentor's full attention is on a single learner,
allowing for a deeper assessment of their real-world problem-solving skills.&lt;/p&gt;
&lt;p&gt;For those seeking job opportunities, online portfolios can be a better proxy for
demonstrating competency. Portfolios showcase projects that require the expected
level of competence, and they offer a chance for learners to prepare and present
their abilities before interviews. While this is not a foolproof method, it
provides a more tangible representation of a learner's potential compared to
mere completion certificates, regardless of the hours invested in a course. One
exception to this is official certifications, which are carefully designed by a
company to ensure professionals are competent in a specific set of tools, e.g.
Microsoft, AWS, Cisco, etc.&lt;/p&gt;
&lt;p&gt;For complete beginners, knowledge, and competency are often acquired
concurrently. However, once competency is established, it can be transferred to
other domains with relative ease. Learning a second programming language, for
instance, becomes more accessible as learners have already grasped general
problem-solving with programming, and they only need to adapt to the specific
syntax of the new language. One exception is when assumptions no longer hold,
for instance, Haskell (or any other pure functional programming language) has
some unique features that require special competencies that may not be easily
obtainable in other languages.&lt;/p&gt;
&lt;p&gt;This roadmap focuses on how to achieve different levels of competence, for that,
consider the &lt;a href="https://www.wikiwand.com/en/Four%20stages%20of%20competence" target="_blank"&gt;Four Stages of
Competence&lt;/a&gt;  plus
some personal contributions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Unconscious Incompetence&lt;/strong&gt;: one is unaware of programming and does not realize
   that it is a learnable skill. They might not even recognize the significance
   of programming in today's world.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conscious Incompetence&lt;/strong&gt;: individuals become aware of programming and its
   importance. However, they struggle to write code and acknowledge their lack
   of proficiency. They are conscious of their limitations and the need to
   improve their skills.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conscious Competence&lt;/strong&gt;: they can write code, but it requires concentration and
   deliberate thinking. They are competent programmers, but the process still
   demands effort and focus.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unconscious Competence&lt;/strong&gt;: programming becomes second nature to learners. They
   can write code effortlessly, with deep knowledge and skill. Their proficiency
   allows them to navigate complex problems seamlessly.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Additional Contributions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Reflective Competence&lt;/strong&gt;: Learners at this stage continually evaluate their
   skills and actively seek to identify their weaknesses. They are self-aware
   and strive to go beyond their comfort zone, taking on challenging projects
   and seeking opportunities for growth and improvement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Replicative Competence&lt;/strong&gt;: Individuals who have achieved replicative competence
   have a profound impact on those around them. They become mentors and role
   models, helping others grow their level of competence exponentially. Their
   expertise and support empower others to excel in their learning journeys.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="unconscious-incompetence-take-off"&gt;&lt;a class="toclink" href="#unconscious-incompetence-take-off"&gt;Unconscious Incompetence - Take Off&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This stage is a universal starting point for every learner, where one realizes,
"I don't know how much I don't know." At this juncture, learners cannot even
articulate what or how to learn next, and it can be a critical phase in the
learning process. The risk of feeling overwhelmed, frustrated, and disappointed
is high, potentially leading to abandoning the learning journey altogether.&lt;/p&gt;
&lt;p&gt;To navigate this crucial stage successfully, I strongly recommend adopting a
Bottom-Up approach. Dedicate around 100 hours to immerse oneself in pure Python
without involving third party libraries, frameworks, or tools other than the
language itself.&lt;/p&gt;
&lt;p&gt;Numerous online resources are available to assist individuals in commencing
their coding endeavors, providing a range of options from which to choose the
most comfortable platform. Utilizing fast-feedback online environments is
recommended, as they allow one to experiment with code and observe errors
without encountering the intricacies of installation and setup. Avoiding such
initial technical challenges can prevent premature disappointment. &lt;/p&gt;
&lt;p&gt;Here are some good free online environments for learning Python (not sponsored):&lt;/p&gt;
&lt;p&gt;Single File:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pythontutor.com/python-debugger.html" target="_blank"&gt;Python Tutor&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.tutorialspoint.com/execute_python3_online.php" target="_blank"&gt;TutorialsPoint&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3schools.com/python/trypython.asp?filename=demo_compiler" target="_blank"&gt;W3
  Schools&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Multi File:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://replit.com/languages/python3" target="_blank"&gt;Replit&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.online-python.com/" target="_blank"&gt;Online Python&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.programiz.com/python-programming/online-compiler/" target="_blank"&gt;Programiz&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Important note&lt;/strong&gt;: Refrain from relying on help tools such as forums, chatbots,
or other guides during this stage. Instead, focus on understanding the
fundamentals of Python - what things are, how they work, and why they behave as
they do. Using AI Chat or similar aids at this point can be likened to learning
multiplication with a calculator; it hinders the learning experience. Save these
tools for later when a more solid foundation has been laid out.&lt;/p&gt;
&lt;p&gt;This stage could be colloquially called "Take Off," as the learner leaves the
ground of total inexperience and begin to graduate from being completely unaware
to having a growing awareness of the Python language. Embrace this initial
learning phase with determination and patience, knowing it will lay the
foundation for future programming prowess.&lt;/p&gt;
&lt;h2 id="conscious-incompetence-consolidation"&gt;&lt;a class="toclink" href="#conscious-incompetence-consolidation"&gt;Conscious Incompetence - Consolidation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Having spent a significant number of hours learning or possessing a background
in programming, learners at this stage can now say, "I know what I don't know."
It may still seem like a daunting task to achieve complete understanding, but
there is a clear awareness of what lies ahead in the learning journey.&lt;/p&gt;
&lt;p&gt;This awareness could be a result of existing programming knowledge in other
languages, prior experience with Python, or expertise in other fields that serve
as a good proxy to estimate the upcoming complexity. Regardless of the source,
there has been significant improvement from the previous stage.&lt;/p&gt;
&lt;p&gt;At this point, I recommend continuing with the Bottom-Up approach, but now
exploring more complex topics, such as popular Python libraries, frameworks, or
design patterns. Focus on well-known and reputable sources, avoiding
experimental or hobbyist projects. Additionally, start engaging with some
Top-Down material that integrates the use of these resources, understanding how
various pieces work together.&lt;/p&gt;
&lt;p&gt;By now, the learner should have a proper Python installation on their local PC,
and dealing with installation challenges is acceptable, as long as they have
learned how to install Python from scratch. However, there is no need to delve
into virtual environments or dependency locking just yet; that can be left for
the next stage.&lt;/p&gt;
&lt;p&gt;For instance, if the learner aims to become a back-end developer, they could
explore the following resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Learn how APIs work (Bottom-Up)&lt;/li&gt;
&lt;li&gt;Learn how Flask work (Bottom-Up)&lt;/li&gt;
&lt;li&gt;Learn how to structure a Flask app (Bottom-Up)&lt;/li&gt;
&lt;li&gt;Develop an ToDo list with Flask (Top-Down)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The focus should remain on learning rather than building fully functional
projects at this stage. Familiarize with the tools and gain intuition on how to
accomplish the desired tasks. This is also a suitable time to start slowly
incorporating tools like AI Chats to aid in the learning process.&lt;/p&gt;
&lt;p&gt;The Consolidation stage may span a couple of months, involving trial and error
and iterative learning, but since the basics are well understood, navigating
through challenges should not be a problem. This stage is aptly named
"Consolidation" as learners solidify their understanding and expand their
programming horizons.&lt;/p&gt;
&lt;h2 id="conscious-competence-portfolio"&gt;&lt;a class="toclink" href="#conscious-competence-portfolio"&gt;Conscious Competence - Portfolio&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One has reached a stage where one understands how the tools work with a
comfortable level of proficiency. The majority of the time was spent learning,
and now it is time to put that knowledge into practice. Bottom-Up materials may
start to feel repetitive, as they cover familiar content.&lt;/p&gt;
&lt;p&gt;In this stage, one finds oneself spending more time reading documentation,
exploring forums, and seeking answers to specific problems rather than following
beginners' tutorials. One has reached the "Intermediate Level," where one
possesses a significant amount of knowledge but may still be lacking some
hands-on experience to fully demonstrate one's competence.&lt;/p&gt;
&lt;p&gt;At this point, it is crucial to shift the focus to "Top-Down" resources. Start
creating a portfolio of projects, building things that one understands and can
confidently explain to others. Share progress on social media or through a blog,
or even consider building a blog as part of a portfolio.&lt;/p&gt;
&lt;p&gt;Some tasks may still be challenging, and the learner might rely on online
tutorials to guide them. Exposure to a variety of projects will help one gain
intuition about how things are done and improve one's problem-solving skills.
However, try to avoid starting everything from scratch. Incorporate virtual
environments and dependency-locking tools like pipenv, poetry, or similar, to
better manage one's projects. This stage is also an excellent opportunity to
learn Git and publish projects as public repositories on GitHub.&lt;/p&gt;
&lt;p&gt;Most of the practical building happens at this stage, which is why it is known
as the "Portfolio" stage. While it is fine to experiment with some new
frameworks, the bulk of the building should be focused on well-established
frameworks and tools. Building a strong portfolio during this stage will not
only enhance one's competence but also provide valuable material to showcase
skills to potential employers or clients.&lt;/p&gt;
&lt;h2 id="unconscious-competence-independence"&gt;&lt;a class="toclink" href="#unconscious-competence-independence"&gt;Unconscious Competence - Independence&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;At this stage, the learner has reached a level of competence where building
projects and navigating the programming world feel like second nature. The
individual can confidently and effortlessly build projects, and their
understanding of how things work is deep-rooted.&lt;/p&gt;
&lt;p&gt;However, there is a caveat to this stage. Maintaining this level of competence
requires continuous practice and engagement. While knowledge may stay with
individuals longer, competency can rust over time if not consistently exercised.
This stage can be risky, as it might lead to stagnation, either intentionally or
unintentionally. When becoming a master at something, a comfort zone naturally
forms around it, and the effort invested in reaching this level can become a
barrier to moving beyond it.&lt;/p&gt;
&lt;p&gt;At this stage, learners can consider themselves "Independent." They are likely
not beginners anymore, but it is essential to avoid limiting oneself to the
comfort zone. Gradually expanding horizons to include more topics and challenges
is recommended. Seeking mentors with extensive knowledge and experience to
provide guidance is beneficial. However, it is crucial to keep in mind that
expecting others to invest time without compensation may not be realistic.
Learners should be proactive in their learning journey.&lt;/p&gt;
&lt;p&gt;This is an excellent time to continue with the Top-Down approach and start
incorporating Experimental learning. Embracing new challenges and exploring
unfamiliar territories is essential. Staying curious and open to learning new
things is advised.&lt;/p&gt;
&lt;p&gt;Nonetheless, this stage represents the first "stable" stage in the learning
journey. Individuals might feel content and comfortable with their current
skills and knowledge, and that's okay. However, remembering that staying in the
comfort zone for too long can make it difficult to make significant moves in the
future is important. Maintaining a balance between expertise and continuous
growth is essential. An example of someone at this stage might be an expert in
an older, less popular language like COBOL. They are competent and independent
in their field and may not feel the need to switch to other technologies as long
as COBOL is still relevant. But this situation is fragile, as the longer one
stays in the same niche, the harder it becomes to transition to something
different.&lt;/p&gt;
&lt;p&gt;Always remembering that expertise is not a free ticket to rest on one's laurels
is crucial. Continuing to push oneself to learn and grow, and being open to
embracing new challenges and opportunities is necessary. Continuous and
conscious action is necessary to prevent unconscious competence from fading into
unconscious incompetence.&lt;/p&gt;
&lt;h2 id="reflective-competence-research-and-development"&gt;&lt;a class="toclink" href="#reflective-competence-research-and-development"&gt;Reflective Competence - Research and Development&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The original model of four stages of competencies does not include a fifth
stage, but some authors have proposed one called "Reflective Competence." At
this stage, individuals not only possess a skill to the point where they can
perform it effortlessly and automatically but also can reflect on their
performance and continuously improve. &lt;/p&gt;
&lt;p&gt;In this stage, one becomes aware and understands their thought process, a
concept known as metacognition. This stage includes the meta-competency of
proactiveness, where individuals can self-assess, take initiative, anticipate
future needs, adapt in advance, and actively seek feedback. Reflective
Competence represents the highest level of individual competency.&lt;/p&gt;
&lt;p&gt;In the technology world, where change is constant, it is crucial to stay
proactive and avoid becoming outdated. To do so, I suggest continuously pushing
oneself outside of the comfort zone, but &lt;a href="https://mcfunley.com/choose-boring-technology" target="_blank"&gt;not too
aggressively&lt;/a&gt;. Engage in learning
new frameworks, trying new tools and methodologies, mentoring others, starting
side projects, getting involved in the community, and contributing to
open-source projects. This stage is known as "Research and Development," and
it's a time to enter "Experimentation" mode.&lt;/p&gt;
&lt;p&gt;Examples of activities during this stage include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If one has mastered relational databases, one can try learning ORMs or NoSQL
  databases.&lt;/li&gt;
&lt;li&gt;If one has mastered Keras, one can explore learning FastAI or Bayesian
  Frameworks.&lt;/li&gt;
&lt;li&gt;If one has mastered Pytest, one can delve into learning Hypothesis.&lt;/li&gt;
&lt;li&gt;If one has mastered Flask, one can consider learning FastAPI.&lt;/li&gt;
&lt;li&gt;If one has mastered Type Hints, one can try learning Pydantic.&lt;/li&gt;
&lt;li&gt;If one has mastered their field's favorite library, one can try fixing some
  issues or developing new features.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Individuals in this stage can act with just small pieces of information; a
simple idea may be enough to spark the whole process, and they can keep the
momentum going. In the industry, these individuals are often referred to by
various names such as "Leaders," "Seniors," "Tech Leads," or "Mentors/Coaches,"
among others. They are valued for their extensive knowledge and their ability to
guide and mentor others.&lt;/p&gt;
&lt;h2 id="replicative-competence-exponential-growth"&gt;&lt;a class="toclink" href="#replicative-competence-exponential-growth"&gt;Replicative Competence - Exponential Growth&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The stage of Replicative Competence is not formal and is a personal
contribution. Once an individual reaches Reflective Competence, there is only
one way to continue growing: horizontally. This stage assumes that one does not
operate in isolation and has people around them.&lt;/p&gt;
&lt;p&gt;Individuals at this stage not only continue to grow themselves but also foster
an environment for efficient, engaging, and motivating growth for everyone
around them.&lt;/p&gt;
&lt;p&gt;This involves several competencies that go beyond the technical side and may not
be something desired by everyone, as previously mentioned, not everyone wants to
leave the IC role. These individuals are characterized by being people who
&lt;strong&gt;C.A.R.E.S&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;C - Competence in the Domain&lt;/strong&gt;: They are experts in the specific domain or skill
  they aim to multiply in others.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A - Adaptive Communication&lt;/strong&gt;: They have effective and adaptable communication
  skills, ensuring clear and relatable knowledge transfer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;R - Relational Empathy&lt;/strong&gt;: They build strong relationships and connect with
  others' needs and emotions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E - Encouraging Patience&lt;/strong&gt;: They cultivate patience and persistence to support
  and guide individuals through their learning journey, even during challenging
  moments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;S - Supportive Coaching&lt;/strong&gt;: They provide constructive feedback, coaching, and
  mentorship, fostering growth and critical thinking in others.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By having an individual at this level on a team, they make it possible for other
team members to grow at a rate that may not have been achievable otherwise. They
enable others and, by doing so, produce "Exponential Growth" within the team.&lt;/p&gt;
&lt;p&gt;This is the stage that any person aspiring for a leadership position should aim
for. People at this level are influential, they lead by example, and they create
a subculture within an organization. They are sought after, and they actively
seek opportunities, not just for themselves, but for the people around them.
They are a never-ending fountain of knowledge and experience, driving continuous
improvement and development in those they interact with.&lt;/p&gt;
&lt;h2 id="self-assessment-and-criticism"&gt;&lt;a class="toclink" href="#self-assessment-and-criticism"&gt;Self-Assessment and Criticism&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Self-assessment is indeed a crucial aspect of the learning process, and it's
important to acknowledge that the roadmap presented in the article may not fully
capture the diverse experiences and perspectives of all learners. While the
article provides a structured approach, it's essential to recognize that
learning is a personal journey, and each individual may have unique preferences,
goals, and constraints.&lt;/p&gt;
&lt;h2 id="begineers-do-not-care"&gt;&lt;a class="toclink" href="#begineers-do-not-care"&gt;Begineers do not Care&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The approach presented in the article is indeed geared towards learners who are
willing to invest time and effort in their learning journey and are looking for
a structured and goal-oriented plan.&lt;/p&gt;
&lt;p&gt;The content's focus on programming and Python is meant to provide concrete
examples and guidance for learners in the technology field, but the underlying
principles and concepts can be adapted to various domains of learning.
Emphasizing that the content is intended for individuals who want a long-term
plan and are committed to their learning journey is crucial. This approach aims
to empower learners to take ownership of their learning, be proactive, and set
realistic goals for continuous improvement.&lt;/p&gt;
&lt;p&gt;Indeed, the value delivered by this content lies in the long-term return and the
gradual internalization of the learning process. By adopting this approach and
incorporating it into their learning style, learners can develop a deeper
understanding and competence in their chosen field, leading to more meaningful
and sustainable growth.&lt;/p&gt;
&lt;p&gt;Ultimately, the approach provided in the article serves as a guide and a
framework, but it is up to each learner to personalize and adapt it according to
their needs, preferences, and learning pace. The willingness to take ownership
and actively engage in the learning process will greatly influence the overall
success and fulfillment of the journey.&lt;/p&gt;
&lt;h2 id="this-is-utopian-and-unrealistic"&gt;&lt;a class="toclink" href="#this-is-utopian-and-unrealistic"&gt;This is Utopian and Unrealistic&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Work, family, travel, personal obligations, and various external factors can
often create time constraints and obstacles that make it difficult to follow a
structured learning plan consistently.&lt;/p&gt;
&lt;p&gt;No guide can indeed address all possible angles and individual circumstances,
and the approach presented in the article may not be feasible for everyone in
every situation. Life is unpredictable, and there will always be unforeseen
challenges and disruptions that can hinder progress.&lt;/p&gt;
&lt;p&gt;However, the value of having a long-term goal and a structured learning approach
lies in the adaptability and resilience it fosters in learners. While it may be
challenging to dedicate extensive time solely to learning, even small steps
taken consistently can lead to significant progress over time. It is about
recognizing that progress may be gradual, and it is okay to make adjustments to
fit learning into one's existing lifestyle and responsibilities.&lt;/p&gt;
&lt;p&gt;Flexibility and adaptability are essential qualities to develop, and having a
loose plan or roadmap can help individuals stay focused and motivated amid the
chaos of life. It provides a sense of direction and purpose, even if the pace of
learning is slower than originally intended.&lt;/p&gt;
&lt;p&gt;Moreover, acknowledging the existence of obstacles and challenges can help
learners be kinder to themselves and avoid unnecessary pressure or guilt when
they face setbacks. It is essential to remember that progress is not always
linear, and it is okay to take breaks, reassess goals, and adapt the learning
approach as needed.&lt;/p&gt;
&lt;p&gt;In the end, the ability to cope with the challenges of the real world and
maintain a commitment to learning is a valuable competency worth cultivating.
Embracing the journey as an ongoing process of growth and self-improvement can
lead to a more fulfilling and meaningful learning experience.&lt;/p&gt;
&lt;h2 id="closing-thoughts"&gt;&lt;a class="toclink" href="#closing-thoughts"&gt;Closing Thoughts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In conclusion, learning is a deeply personal and individualized journey. There
is no one-size-fits-all approach, and it is crucial to be aware of your
strengths, weaknesses, and learning style. Building a roadmap that aligns with
your preferences and comfort levels can lead to a more effective and enjoyable
learning experience.&lt;/p&gt;
&lt;p&gt;While there are abundant learning resources available online, it is essential to
approach them with a critical mindset. Not all information is reliable, and not
all approaches will work for everyone. Seeking feedback from experienced
individuals and questioning your assumptions can help you refine your learning
path and avoid falling into confirmation bias.&lt;/p&gt;
&lt;p&gt;Moreover, it is crucial to strike a balance between seeking guidance and
exploring on your own. Relying solely on pre-packaged solutions may limit your
growth, but venturing into uncharted territory without any guidance may lead to
frustration and discouragement. Embrace a mix of structured learning and
experimentation to foster a well-rounded and adaptable skill set.&lt;/p&gt;
&lt;p&gt;Lastly, be open to challenging your beliefs and exploring different
perspectives. Exposing yourself to diverse ideas and viewpoints can help you
grow intellectually and creatively. Embrace a growth mindset, be receptive to
feedback, and never stop seeking opportunities for learning and improvement.&lt;/p&gt;
&lt;p&gt;In the end, the journey of learning is an ongoing and enriching process. Embrace
the challenges, celebrate your progress, and keep pushing yourself to reach new
levels of competence. Remember that the path to mastery is not always smooth,
but it is the continuous pursuit of knowledge and self-improvement that leads to
true expertise.&lt;/p&gt;</content><category term="Programming"></category><category term="Python"></category><category term="learning"></category></entry><entry><title>Python Recursion: a Trampoline from the Mutual Head to the Memoized Nested Tail</title><link href="https://elc.github.io/posts/recursion-python" rel="alternate"></link><published>2023-05-21T00:00:00-03:00</published><updated>2023-05-21T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2023-05-21:/posts/recursion-python</id><summary type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive-python_headerimage.png"&gt;&lt;img alt="Recursion in Python" class="b-lazy" data-src="/blog/images/recursion/recursive-python_headerimage.png" src="https://elc.github.io/blog/images/recursion/recursive-python_headerimage-thumbnail.png" width="1444"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Recursion is a key concept of programming. However, it is usually only
superficially explored. There are different ways of having recursion, this post
will illustrate them using Python examples, call graphs and step-by-step runs.
Including cases of head, tail, nested and mutual recursion. For each case, the
call graph will …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive-python_headerimage.png"&gt;&lt;img alt="Recursion in Python" class="b-lazy" data-src="/blog/images/recursion/recursive-python_headerimage.png" src="https://elc.github.io/blog/images/recursion/recursive-python_headerimage-thumbnail.png" width="1444"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Recursion is a key concept of programming. However, it is usually only
superficially explored. There are different ways of having recursion, this post
will illustrate them using Python examples, call graphs and step-by-step runs.
Including cases of head, tail, nested and mutual recursion. For each case, the
call graph will be shown.&lt;/p&gt;


&lt;p&gt;Content covered in this post:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#an-old-friend-the-factorial"&gt;An old friend: The Factorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#recursion"&gt;Recursion&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#why-recursion"&gt;Why Recursion?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#direct-vs-indirect-recursion"&gt;Direct vs Indirect Recursion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#linear-recursion"&gt;Linear Recursion&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#tail-recursion"&gt;Tail Recursion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#multi-recursion"&gt;Multi Recursion&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#general-non-linear-recursion"&gt;General Non-Linear Recursion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#tree-recursion"&gt;Tree Recursion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#converting-non-tree-recursion-into-tree-recursion"&gt;Converting non-tree recursion into tree recursion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#nested-recursion"&gt;Nested Recursion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#triple-nested-recursion"&gt;Triple Nested Recursion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#nested-recursion-with-more-than-one-argument"&gt;Nested Recursion with more than one argument&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#indirect-recursion"&gt;Indirect Recursion&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#mutual-linear-recursion"&gt;Mutual Linear Recursion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#mutual-multi-recursion"&gt;Mutual Multi Recursion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#mutual-nested-recursion"&gt;Mutual Nested Recursion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#mutual-triple-recursion"&gt;Mutual Triple Recursion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#recursion-related-techniques"&gt;Recursion related techniques&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#memoization"&gt;Memoization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#memoization-examples"&gt;Memoization Examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#trampolining"&gt;Trampolining&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#call-by-need"&gt;Call-By-Need&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="an-old-friend-the-factorial"&gt;&lt;a class="toclink" href="#an-old-friend-the-factorial"&gt;An old friend: The Factorial&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many if not all programming courses introduce the factorial function at some
point. This function has great mathematical importance and yet it is simple
enough to showcase how recursion works. However, the approach towards it and
recursion, in general, is usually superficial.&lt;/p&gt;
&lt;p&gt;Before digging into recursion, a procedural implementation using for-loops and
while loops will be shown.&lt;/p&gt;
&lt;h3 id="side-note"&gt;&lt;a class="toclink" href="#side-note"&gt;Side Note&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This post abuses the fact that, in Python, when a function is defined multiple
times only the last definition is used for future references. There will be many
refinements over the definitions and to avoid any confusion, names will not be
changed to reflect that, they all do the same. To further reinforce this idea,
an assert statement will be added to show that results do not change even if the
definition changes.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20factorial%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22Factorial%20function%20implemented%20using%20for%3Dloop%22%22%22%0A%20%20%20%20result%20%3D%201%0A%20%20%20%20for%20i%20in%20range%281,%20n%20%2B%201%29%3A%0A%20%20%20%20%20%20%20%20result%20*%3D%20i%0A%20%20%20%20return%20result%0A%0Aactual%20%3D%20%5Bfactorial%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B1,%201,%202,%206,%2024,%20120,%20720%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Factorial function implemented using for loops&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;720&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And next the while loop equivalent:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20factorial%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22Factorial%20function%20using%20while-loop%22%22%22%0A%20%20%20%20result%20%3D%201%0A%20%20%20%20multiplier%20%3D%20n%0A%20%20%20%20while%20multiplier%20!%3D%200%3A%0A%20%20%20%20%20%20%20%20result%20*%3D%20multiplier%0A%20%20%20%20%20%20%20%20multiplier%20-%3D%201%0A%20%20%20%20return%20result%0A%0Aactual%20%3D%20%5Bfactorial%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B1,%201,%202,%206,%2024,%20120,%20720%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Factorial function implemented using while loops&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;multiplier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;multiplier&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="n"&gt;multiplier&lt;/span&gt;
        &lt;span class="n"&gt;multiplier&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;720&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Between the for loop and the while loop implementation differences are visible.
The for-loop approach is usually the one found in many sources online, it is
short, uses only basic constructs and does the job. Whereas the while approach
uses one extra variable, that being said, both are valid and share the same time
and space complexity.&lt;/p&gt;
&lt;p&gt;Another possibility, not as common as the previous ones, is a functional
implementation using &lt;code&gt;reduce&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20functools%20import%20reduce%0A%0Adef%20factorial%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22Factorial%20function%20using%20reduce%22%22%22%0A%20%20%20%20return%20reduce%28%0A%20%20%20%20%20%20%20%20lambda%20x,%20y%3A%20x%20*%20y,%0A%20%20%20%20%20%20%20%20range%281,%20n%20%2B%201%29,%0A%20%20%20%20%20%20%20%201%0A%20%20%20%20%29%0A%0Aactual%20%3D%20%5Bfactorial%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B1,%201,%202,%206,%2024,%20120,%20720%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;reduce&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Factorial function implemented using reduce&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;720&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since the previous implementations are non-recursive, the &lt;a href="https://en.wikipedia.org/wiki/Call_graph" target="_blank"&gt;call
graph&lt;/a&gt;  consists of
a single node:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/non_recursive_factorial.png"&gt;&lt;img alt="Non-Recursive Factorial Call Graph" class="narrow b-lazy" data-src="/blog/images/recursion/non_recursive_factorial.png" src="https://elc.github.io/blog/images/recursion/non_recursive_factorial-thumbnail.png" width="554"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="recursion"&gt;&lt;a class="toclink" href="#recursion"&gt;Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After introducing one of the previous definitions of the factorial function, the
"recursive form" is usually presented. A recursive function is a function that
calls itself. There are multiple types of recursion though, and understanding
them may have a huge impact on some programming languages. Before showing what
the recursive version of the factorial looks like, it is important to clarify
some concepts.&lt;/p&gt;
&lt;h2 id="why-recursion"&gt;&lt;a class="toclink" href="#why-recursion"&gt;Why Recursion?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Recursion in and of itself is a wide field in computer science that may attract
scientists and researchers. However, it is sometimes portrayed as a difficult
topic and receives less attention than other techniques. &lt;/p&gt;
&lt;p&gt;Although some may avoid recursion altogether, there are clear and noticeable
benefits of using recursive functions, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Declarative style&lt;/strong&gt;: Recursive functions are written by thinking about
  &lt;strong&gt;what&lt;/strong&gt; the function does instead of &lt;strong&gt;how&lt;/strong&gt; it does it. The iterative style
  usually leads the programmer to think about low-level details like indexes and
  pointers whereas recursion brings the whole problem into mind.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplicity and Readability&lt;/strong&gt;: Recursive functions can provide a more elegant
  and concise solution for solving complex problems by breaking them down into
  simpler subproblems. The recursive approach often closely resembles the
  problem's definition, making the code more intuitive and easier to understand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Divide and Conquer&lt;/strong&gt;: Recursive functions can leverage the divide and
  conquer technique, where a problem is divided into smaller subproblems that
  are solved independently. This approach simplifies the problem-solving process
  by reducing complex tasks into manageable pieces.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code Reusability&lt;/strong&gt;: Recursive functions are often reusable. Once
  implemented, they can be called multiple times with different inputs, allowing
  for efficient and modular code. Recursive functions can be applied to various
  instances of the same problem, enabling code reuse and promoting good software
  engineering practices.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handling Recursive Structures&lt;/strong&gt;: Recursive functions are especially useful
  when dealing with recursive data structures, such as trees or linked lists.
  The recursive nature of the data can be mirrored in the recursive functions,
  making it easier to traverse, manipulate, or process such structures.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mathematical and Algorithmic Modeling&lt;/strong&gt;: Many mathematical and algorithmic
  problems are naturally defined in terms of recursion. Recursive functions
  provide a natural and direct way to express these problems, making the code
  more closely aligned with the underlying mathematical or algorithmic concepts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Time and Space Optimization&lt;/strong&gt;: Recursive functions can often lead to more
  efficient algorithms in terms of time and space complexity. By breaking down a
  problem into smaller subproblems, recursive functions can avoid unnecessary
  computations by reusing previously calculated results (memoization) or
  eliminating redundant iterations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="direct-vs-indirect-recursion"&gt;&lt;a class="toclink" href="#direct-vs-indirect-recursion"&gt;Direct vs Indirect Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Most commonly, when one says "recursive function", it is meant "direct recursive
function", that is, the function calls itself. The other way a function could be
recursive is through "indirect recursion" where, instead of calling itself, it
calls another function (or chain of functions) that will in turn call the first
function.&lt;/p&gt;
&lt;p&gt;Different types of direct recursions worth mentioning are:&lt;/p&gt;
&lt;p&gt;Based on where the recursive call is done:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Head Recursion&lt;/li&gt;
&lt;li&gt;Middle Recursion&lt;/li&gt;
&lt;li&gt;Tail Recursion&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Based on the number of recursive calls:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linear Recursion&lt;/li&gt;
&lt;li&gt;Multi Recursion (also called nonlinear or exponential recursion)&lt;ul&gt;
&lt;li&gt;Tree Recursion (also called bifurcating recursion)&lt;/li&gt;
&lt;li&gt;Nested Recursion&lt;/li&gt;
&lt;li&gt;General Non-Linear Recursion&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Based on the number of functions involved:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Direct Recursion (a single function)&lt;/li&gt;
&lt;li&gt;Indirect Recursion (multiple functions, also called mutual recursion)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Besides the previous classification, all recursive functions must have a
termination condition or else they would enter in an infinite loop. Even though
recursive functions do not need to be pure (i.e. they do not have side effects),
it is common for recursive functions to be pure, this simplifies the
interpretation. All the examples in this article are pure functions.&lt;/p&gt;
&lt;h2 id="linear-recursion"&gt;&lt;a class="toclink" href="#linear-recursion"&gt;Linear Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Linear recursion refers to functions where there is &lt;strong&gt;only one recursive call&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Based on the position of the recursive call it could be further subdivided into:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Head Recursion: recursive call is the first statement.&lt;/li&gt;
&lt;li&gt;Middle Recursion: there are other statements before and after a recursive
  call.&lt;/li&gt;
&lt;li&gt;Tail Recursion: recursive call is the last statement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is no difference between Middle Recursion and Head Recursion from an
efficiency and algorithmic perspective. So no further exploration will not be
done on those two.&lt;/p&gt;
&lt;p&gt;When a function has more than one recursive call is called Multi Recursion,
Nonlinear Recursion or Exponential Recursion. These cases will be covered in a
later section.&lt;/p&gt;
&lt;p&gt;The following is an example of a middle recursion implementation of the
factorial function.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20factorial%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22Middle%20Recursion%20of%20the%20factorial%20function%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20n%20*%20factorial%28n%20-%201%29%0A%0Aactual%20%3D%20%5Bfactorial%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B1,%201,%202,%206,%2024,%20120,%20720%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Middle Recursion implementation of the factorial function&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;720&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It is middle recursion because the last statement is a multiplication (&lt;code&gt;*&lt;/code&gt;) and
not the recursive call itself. Depending on the operation order it could also be
considered head recursion but that difference is not relevant for most contexts.&lt;/p&gt;
&lt;p&gt;Another way to better show why this is middle recursion is to use additional
variables to store interim results:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20factorial%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22Middle%20Recursion%20of%20the%20factorial%20function%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20previous_factorial%20%3D%20factorial%28n%20-%201%29%0A%20%20%20%20current_factorial%20%3D%20n%20*%20previous_factorial%0A%20%20%20%20return%20current_factorial%0A%0Aactual%20%3D%20%5Bfactorial%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B1,%201,%202,%206,%2024,%20120,%20720%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Middle Recursion implementation of the factorial function&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;previous_factorial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;current_factorial&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;previous_factorial&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;current_factorial&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;720&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this more explicit implementation, it is clearer that the last logical
statement is the multiplication &lt;code&gt;n * previous_factorial&lt;/code&gt;. &lt;/p&gt;
&lt;p&gt;The call graph in the case of linear recursive functions is a series of nodes
called sequentially, hence the name:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_factorial.png"&gt;&lt;img alt="Recursive Factorial Call Graph" class="narrow b-lazy" data-src="/blog/images/recursion/recursive_factorial.png" src="https://elc.github.io/blog/images/recursion/recursive_factorial-thumbnail.png" width="200"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When the last statement is the recursive call, the function is called tail
recursion, which will be explored in the next section.&lt;/p&gt;
&lt;h2 id="tail-recursion"&gt;&lt;a class="toclink" href="#tail-recursion"&gt;Tail Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Tail recursion is when the return statement of the function is &lt;strong&gt;only a
recursive call&lt;/strong&gt;, this means that a function call could be replaced with another
function call directly. Some languages (Python is not one of them), use a
technique named &lt;a href="https://en.wikipedia.org/wiki/Tail_call" target="_blank"&gt;Tail-Call
Optimization&lt;/a&gt;, which
makes this particular type of recursion very efficient.&lt;/p&gt;
&lt;p&gt;One important clarification is that the return &lt;strong&gt;must not be an expression&lt;/strong&gt;. An
example of a straightforward function that can be implemented in a tail
recursive way is the &lt;code&gt;palindrome&lt;/code&gt; function:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20palindrome%28string%3A%20str%29%20-%3E%20bool%3A%0A%20%20%20%20%22%22%22Returns%20True%20if%20the%20given%20string%20is%20a%20%0A%20%20%20%20palindrome.%20Using%20tail%20recursion.%22%22%22%0A%20%20%20%20if%20len%28string%29%20%3C%202%3A%0A%20%20%20%20%20%20%20%20return%20True%0A%0A%20%20%20%20first,%20*rest,%20last%20%3D%20string%0A%20%20%20%20if%20first%20!%3D%20last%3A%0A%20%20%20%20%20%20%20%20return%20False%0A%20%20%20%20return%20palindrome%28rest%29%0A%0Aassert%20palindrome%28%22a%22%29%0Aassert%20palindrome%28%22aa%22%29%0Aassert%20palindrome%28%22aba%22%29%0Aassert%20not%20palindrome%28%22learn%22%29%0Aassert%20palindrome%28%22rotator%22%29&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;Returns True if the given string is a palindrome. Using tail recursion.&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;

    &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aa&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aba&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;learn&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rotator&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_palindrome.png"&gt;&lt;img alt="Recursive Palindrome" class="narrow b-lazy" data-src="/blog/images/recursion/recursive_palindrome.png" src="https://elc.github.io/blog/images/recursion/recursive_palindrome-thumbnail.png" width="600"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To better illustrate the fact that the returning statement must be &lt;strong&gt;only a
function call&lt;/strong&gt;, the following implementation is &lt;strong&gt;NOT&lt;/strong&gt; a tail recursive
function because the last statement is not a function call, it is a boolean
expression that requires the function call to be executed before returning. The
reason is the &lt;code&gt;and&lt;/code&gt; operator which needs a value. This implementation is
therefore a middle recursion.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20palindrome%28string%3A%20str%29%20-%3E%20bool%3A%0A%20%20%20%20%22%22%22Returns%20True%20if%20the%20given%20string%20is%20%0A%20%20%20%20a%20palindrome.%20Using%20middle%20recursion.%22%22%22%0A%20%20%20%20if%20len%28string%29%20%3C%202%3A%0A%20%20%20%20%20%20%20%20return%20True%0A%0A%20%20%20%20first,%20*rest,%20last%20%3D%20string%0A%20%20%20%20return%20first%20%3D%3D%20last%20and%20palindrome%28rest%29%0A%0Aassert%20palindrome%28%22a%22%29%0Aassert%20palindrome%28%22aa%22%29%0Aassert%20palindrome%28%22aba%22%29%0Aassert%20not%20palindrome%28%22learn%22%29%0Aassert%20palindrome%28%22rotator%22%29&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;Returns True if the given string is a palindrome. Using middle recursion.&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;

    &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aa&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;aba&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;learn&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;palindrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rotator&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Sometimes a function that is not expressed in tail-call form can be converted to
that form. For example the following middle recursive function:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20sum_integer_up_to_n%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22Sums%20all%20integers%20from%20zero%20to%20n.%20%0A%20%20%20%20Using%20middle%20recursion%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20%0A%20%20%20%20return%20n%20%2B%20sum_integer_up_to_n%28n%20-%201%29%0A%0Aassert%20sum_integer_up_to_n%281%29%20%3D%3D%201%0Aassert%20sum_integer_up_to_n%283%29%20%3D%3D%206&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sum_integer_up_to_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Sums all integers from zero to n. Using middle recursion&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;sum_integer_up_to_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;sum_integer_up_to_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;sum_integer_up_to_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_sum_integer_up_to_n.png"&gt;&lt;img alt="Recursive Sum Integer up to N" class="narrow b-lazy" data-src="/blog/images/recursion/recursive_sum_integer_up_to_n.png" src="https://elc.github.io/blog/images/recursion/recursive_sum_integer_up_to_n-thumbnail.png" width="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Can be rewritten into tail-recursive form as:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20sum_integer_up_to_n%28n%3A%20int,%20total%3A%20int%20%3D%200%29%20-%3E%20int%3A%0A%20%20%20%20%22%22%22Sums%20all%20integers%20from%20zero%20to%20n.%20%0A%20%20%20%20Using%20Tail%20recursion%22%22%22%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20total%0A%0A%20%20%20%20return%20sum_integer_up_to_n%28n%20-%201,%20total%3Dn%20%2B%20total%29%0A%0Aassert%20sum_integer_up_to_n%281%29%20%3D%3D%201%0Aassert%20sum_integer_up_to_n%283%29%20%3D%3D%206&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sum_integer_up_to_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Sums all integers from zero to n. Using Tail recursion&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sum_integer_up_to_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;sum_integer_up_to_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;sum_integer_up_to_n&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/tail_recursive_sum_integer_up_to_n.png"&gt;&lt;img alt="Recursive Sum Integer up to N" class="narrow b-lazy" data-src="/blog/images/recursion/tail_recursive_sum_integer_up_to_n.png" src="https://elc.github.io/blog/images/recursion/tail_recursive_sum_integer_up_to_n-thumbnail.png" width="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This last version uses an additional parameter to pass the total down the call
chain. This compromises readability for performance if the language implements
tail-call optimization. This style of programming is widely used in languages
like Prolog and some purely-functional languages.&lt;/p&gt;
&lt;p&gt;In Python however the extra parameter can be &lt;em&gt;hidden&lt;/em&gt; by using default values,
this makes the implementation more similar to the original but it is implicitly
hiding the way it truly works, which is against many coding styles. Use with
caution.&lt;/p&gt;
&lt;p&gt;In the same way as &lt;code&gt;sum_integer_up_to_n&lt;/code&gt;, the factorial function could be
re-written into a tail recursive form:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20factorial%28n%3A%20int,%20result%3A%20int%20%3D%201%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20result%0A%0A%20%20%20%20return%20factorial%28n%20-%201,%20n%20*%20result%29%0A%0Aactual%20%3D%20%5Bfactorial%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B1,%201,%202,%206,%2024,%20120,%20720%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;720&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/tail_recursive_factorial.png"&gt;&lt;img alt="Tail Recursive Factorial" class="narrow b-lazy" data-src="/blog/images/recursion/tail_recursive_factorial.png" src="https://elc.github.io/blog/images/recursion/tail_recursive_factorial-thumbnail.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When comparing head/middle with tail recursion, the way each approach works
differs and can be illustrated by inspecting the execution step by step: &lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Head/Middle Recursion&lt;/span&gt;
&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="mi"&gt;6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Tail Recursion&lt;/span&gt;
&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;factorial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;6&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="multi-recursion"&gt;&lt;a class="toclink" href="#multi-recursion"&gt;Multi Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When there is more than one recursive call, a function is said to be
multi-recursive. Multi-recursive functions can also be middle/head recursive or
tail-recursive. A special case of Multi Recursion is when the recursive call is
one of the arguments, in this case, it is referred to as nested recursive.&lt;/p&gt;
&lt;h2 id="general-non-linear-recursion"&gt;&lt;a class="toclink" href="#general-non-linear-recursion"&gt;General Non-Linear Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many functions do not follow a precise pattern and they just use multiple
recursive calls as part of their definition. One such example is a function that
returns the nth Fibonacci number, to call the function two successive recursive
calls are used.&lt;/p&gt;
&lt;p&gt;This is the traditional implementation:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20fibonacci%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20fibonacci%28n-1%29%20%2B%20fibonacci%28n-2%29%0A%0Aactual%20%3D%20%5Bfibonacci%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B0,%201,%201,%202,%203,%205,%208%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_fibonacci.png"&gt;&lt;img alt="Multi Recursive Fibonacci" class="b-lazy" data-src="/blog/images/recursion/recursive_fibonacci.png" src="https://elc.github.io/blog/images/recursion/recursive_fibonacci-thumbnail.png" width="2750"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In some cases, multi-recursive functions can be refactored into linear tail
recursive functions.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20fibonacci%28%0A%20%20%20%20n%3A%20int,%20partial_result%3A%20int%20%3D%200,%20result%3A%20int%20%3D%201%0A%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%20result%0A%20%20%20%20return%20fibonacci%28%0A%20%20%20%20%20%20%20%20n%3Dn%20-%201,%0A%20%20%20%20%20%20%20%20partial_result%3Dresult,%0A%20%20%20%20%20%20%20%20result%3Dpartial_result%20%2B%20result%0A%20%20%20%20%29%0A%0Aactual%20%3D%20%5Bfibonacci%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B0,%201,%201,%202,%203,%205,%208%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;partial_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;partial_result&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/tail_recursive_fibonacci.png"&gt;&lt;img alt="Fibonacci Tail Recursive" class="narrow b-lazy" data-src="/blog/images/recursion/tail_recursive_fibonacci.png" src="https://elc.github.io/blog/images/recursion/tail_recursive_fibonacci-thumbnail.png" width="300"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="tree-recursion"&gt;&lt;a class="toclink" href="#tree-recursion"&gt;Tree Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the case of multi-recursive functions, it is possible to construct a tree of
the function calls. All multi-recursive functions produce a tree, that being
said, in some cases the definition leverages the divide-and-conquer strategy,
minimizing the depth of the tree. One example of this is the quicksort
algorithm:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20typing%20import%20Collection,%20List%0A%0Adef%20quicksort%28%0A%20%20%20%20numbers%3A%20Collection%5Bfloat%5D%0A%29%20-%3E%20List%5Bfloat%5D%3A%0A%20%20%20%20if%20len%28numbers%29%20%3C%3D%201%3A%0A%20%20%20%20%20%20%20%20return%20numbers%0A%0A%20%20%20%20first,%20*rest%20%3D%20numbers%0A%0A%20%20%20%20left%20%3D%20%5Bx%20for%20x%20in%20rest%20if%20x%20%3C%20first%5D%0A%20%20%20%20right%20%3D%20%5Bx%20for%20x%20in%20rest%20if%20x%20%3E%3D%20first%5D%0A%20%20%20%20return%20quicksort%28left%29%20%2B%20%5Bfirst%5D%20%2B%20quicksort%28right%29%0A%0Aactual%20%3D%20quicksort%28%5B2,%204,%203,%205,%200,%201%5D%29%0Aexpected%20%3D%20list%28range%286%29%29%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Collection&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;quicksort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;

    &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;

    &lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;quicksort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;quicksort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;quicksort&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;quicksort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;reversed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_quicksort.png"&gt;&lt;img alt="Tree recursive quicksort" class="b-lazy" data-src="/blog/images/recursion/recursive_quicksort.png" src="https://elc.github.io/blog/images/recursion/recursive_quicksort-thumbnail.png" width="2710"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here the function divides the input into two parts and each recursive call gets
one of the parts. This strategy reduces the number of recursive calls by a great
amount.&lt;/p&gt;
&lt;h2 id="converting-non-tree-recursion-into-tree-recursion"&gt;&lt;a class="toclink" href="#converting-non-tree-recursion-into-tree-recursion"&gt;Converting non-tree recursion into tree recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some functions that are originally linear recursive can be converted into tree
recursive to reduce the depth of the recursive stack. This is usually easy on
functions that operate on arrays.&lt;/p&gt;
&lt;p&gt;Here is a linear recursive implementation of a function that returns the maximum
value of a list:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20typing%20import%20Iterable%0A%0Adef%20maximum%28numbers%3A%20Iterable%5Bfloat%5D%29%20-%3E%20float%3A%0A%20%20%20%20first,%20*rest%20%3D%20numbers%0A%20%20%20%20if%20not%20rest%3A%0A%20%20%20%20%20%20%20%20return%20first%0A%0A%20%20%20%20rest_max%20%3D%20maximum%28rest%29%0A%20%20%20%20return%20first%20if%20first%20%3E%20rest_max%20else%20rest_max%0A%0Aassert%20maximum%28%5B2,%204,%203,%205,%200,%201%5D%29%20%3D%3D%205%0Aassert%20maximum%28list%28range%2810%29%29%29%20%3D%3D%209&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;

    &lt;span class="n"&gt;rest_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;rest_max&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;rest_max&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_maximum.png"&gt;&lt;img alt="Maximum Linear recursion" class="narrow b-lazy" data-src="/blog/images/recursion/recursive_maximum.png" src="https://elc.github.io/blog/images/recursion/recursive_maximum-thumbnail.png" width="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This holds even if re-written into a tail-recursive form:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20typing%20import%20Optional,%20Iterable%0A%0Adef%20maximum%28%0A%20%20%20%20numbers%3A%20Iterable%5Bfloat%5D,%0A%20%20%20%20max_value%3A%20Optional%5Bfloat%5D%20%3D%20None%0A%29%20-%3E%20float%3A%0A%20%20%20%20first,%20*rest%20%3D%20numbers%0A%0A%20%20%20%20if%20max_value%20is%20None%20or%20first%20%3E%20max_value%3A%0A%20%20%20%20%20%20%20%20max_value%20%3D%20first%0A%0A%20%20%20%20if%20not%20rest%3A%0A%20%20%20%20%20%20%20%20return%20max_value%0A%0A%20%20%20%20return%20maximum%28rest,%20max_value%29%0A%0Aassert%20maximum%28%5B2,%204,%203,%205,%200,%201%5D%29%20%3D%3D%205&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;max_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;max_value&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;max_value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;max_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;max_value&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_maximum_tail.png"&gt;&lt;img alt="Maximum Linear tail recursion" class="narrow b-lazy" data-src="/blog/images/recursion/recursive_maximum_tail.png" src="https://elc.github.io/blog/images/recursion/recursive_maximum_tail-thumbnail.png" width="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Both implementations will have as many recursive calls as there are elements in
the list. A similar approach to the quicksort algorithm can be used to reduce
the number of calls, halving the length of the list each time. With this
approach, the recursive stack will be shorter.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20typing%20import%20Collection%0A%0Adef%20maximum%28numbers%3A%20Collection%5Bfloat%5D%29%20-%3E%20float%3A%0A%20%20%20%20first,%20*rest%20%3D%20numbers%0A%20%20%20%20if%20not%20rest%3A%0A%20%20%20%20%20%20%20%20return%20first%0A%0A%20%20%20%20middle%20%3D%20len%28numbers%29%20//%202%0A%20%20%20%20left_max%20%3D%20maximum%28numbers%5B%3Amiddle%5D%29%0A%20%20%20%20right_max%20%3D%20maximum%28numbers%5Bmiddle%3A%5D%29%0A%20%20%20%20%0A%20%20%20%20if%20left_max%20%3E%20right_max%3A%0A%20%20%20%20%20%20%20%20return%20left_max%0A%20%20%20%20return%20right_max%0A%0Aassert%20maximum%28%5B2,%204,%203,%205,%200,%201%5D%29%20%3D%3D%205%0Aassert%20maximum%28list%28range%2810%29%29%29%20%3D%3D%209&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Collection&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Collection&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;numbers&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt;

    &lt;span class="n"&gt;middle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;left_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;middle&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;right_max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;numbers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;middle&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;left_max&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;left_max&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;right_max&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;right_max&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/tree_recursive_maximum.png"&gt;&lt;img alt="Maximum Tree Recursion" class="b-lazy" data-src="/blog/images/recursion/tree_recursive_maximum.png" src="https://elc.github.io/blog/images/recursion/tree_recursive_maximum-thumbnail.png" width="3260"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Refactoring functions this way is not always possible, for functions like nth
Fibonacci, it is not trivial to use a tree approach that reduces the number of
recursive calls. A known solution called Fast Doubling has been discovered.
Deriving this implementation requires a lot of effort and mathematical
knowledge, such an approach may not apply to other functions.&lt;/p&gt;
&lt;p&gt;The Fast Doubling Implementation is as follows:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20fibonacci%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%23%20Fast%20Doubling%20Method%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20%0A%20%20%20%20is_odd%20%3D%20n%20%25%202%0A%20%20%20%20m%20%3D%20n%20//%202%20%2B%20is_odd%0A%20%20%20%20fib_m%20%3D%20fibonacci%28m%29%0A%20%20%20%20fib_m_1%20%3D%20fibonacci%28m%20-%201%29%0A%0A%20%20%20%20if%20is_odd%3A%0A%20%20%20%20%20%20%20%20return%20fib_m_1%20**%202%20%2B%20fib_m%20**%202%0A%20%20%20%20return%202%20*%20fib_m%20*%20fib_m_1%20%2B%20fib_m%20**%202%0A%0Aactual%20%3D%20%5Bfibonacci%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B0,%201,%201,%202,%203,%205,%208%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Fast Doubling Method&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="n"&gt;is_odd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;is_odd&lt;/span&gt;
    &lt;span class="n"&gt;fib_m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fib_m_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_odd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fib_m_1&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fib_m&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fib_m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fib_m_1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fib_m&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/fast_double_fibonacci.png"&gt;&lt;img alt="Fast Double Fibonacci" class="narrow b-lazy" data-src="/blog/images/recursion/fast_double_fibonacci.png" src="https://elc.github.io/blog/images/recursion/fast_double_fibonacci-thumbnail.png" width="700"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It is even possible to further reduce the number of recursive calls by
converting the multi-recursive function into a linear recursive function by
changing its structure to return two values at once:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20typing%20import%20Tuple%0A%0Adef%20fibonacci%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20def%20nth_and_nth_plus_one%28%0A%20%20%20%20%20%20%20%20n%3A%20int%0A%20%20%20%20%29%20-%3E%20Tuple%5Bint,%20int%5D%3A%0A%20%20%20%20%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%200,%201%0A%0A%20%20%20%20%20%20%20%20fib_m,%20fib_m_1%20%3D%20nth_and_nth_plus_one%28n%20//%202%29%0A%20%20%20%20%20%20%20%20nth%20%3D%20fib_m%20*%20fib_m_1%20*%202%20-%20fib_m%20**%202%0A%20%20%20%20%20%20%20%20nth_plus_one%20%3D%20fib_m%20**%202%20%2B%20fib_m_1%20**%202%0A%0A%20%20%20%20%20%20%20%20is_odd%20%3D%20n%20%25%202%0A%20%20%20%20%20%20%20%20if%20is_odd%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20nth_plus_two%20%3D%20nth%20%2B%20nth_plus_one%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20nth_plus_one,%20nth_plus_two%0A%20%20%20%20%20%20%20%20return%20nth,%20nth_plus_one%0A%0A%20%20%20%20nth,%20_%20%3D%20nth_and_nth_plus_one%28n%29%0A%20%20%20%20return%20nth%0A%0Aactual%20%3D%20%5Bfibonacci%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B0,%201,%201,%202,%203,%205,%208%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# based on: https://www.nayuki.io/page/fast-fibonacci-algorithms&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;nth_and_nth_plus_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="n"&gt;fib_m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fib_m_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nth_and_nth_plus_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;nth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fib_m&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fib_m_1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;fib_m&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="n"&gt;nth_plus_one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fib_m&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fib_m_1&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;

        &lt;span class="n"&gt;is_odd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_odd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;nth_plus_two&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nth&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;nth_plus_one&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;nth_plus_one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nth_plus_two&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nth_plus_one&lt;/span&gt;

    &lt;span class="n"&gt;nth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nth_and_nth_plus_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;nth&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/efficient_recursive_fibonacci.png"&gt;&lt;img alt="Linear Recursive Fibonacci" class="narrow b-lazy" data-src="/blog/images/recursion/efficient_recursive_fibonacci.png" src="https://elc.github.io/blog/images/recursion/efficient_recursive_fibonacci-thumbnail.png" width="400"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Even though in these examples with &lt;code&gt;fibonacci(4)&lt;/code&gt; the difference is not drastic,
the number of total calls in the call graph scales in notoriously different ways
for each implementation, take for example &lt;code&gt;fibonacci(100)&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Typical Multi Recursive Implementation: 1,146,295,688,027,634,168,203 calls ≈ 1 sextillion calls&lt;/li&gt;
&lt;li&gt;Fast Doubles: 163 calls&lt;/li&gt;
&lt;li&gt;Tail Recursive Implementation: 100 calls&lt;/li&gt;
&lt;li&gt;Linear Recursive Implementation: 8 calls&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="nested-recursion"&gt;&lt;a class="toclink" href="#nested-recursion"&gt;Nested Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One special case of multi-recursion is when the argument of the recursive call
is itself a recursive call. This is not usual in software development but could
arise in mathematical fields. One example is the &lt;a href="https://mathworld.wolfram.com/HofstadterG-Sequence.html" target="_blank"&gt;Hofstadter G Sequence&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20hofstadter_g%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20return%20n%20-%20hofstadter_g%28hofstadter_g%28n%20-%201%29%29%0A%0Aactual%20%3D%20%5Bhofstadter_g%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B0,%201,%201,%202,%203,%203,%204%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hofstadter_g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;hofstadter_g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hofstadter_g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hofstadter_g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_hofstadter_g.png"&gt;&lt;img alt="Recursive Hofstadter G" class="b-lazy" data-src="/blog/images/recursion/recursive_hofstadter_g.png" src="https://elc.github.io/blog/images/recursion/recursive_hofstadter_g-thumbnail.png" width="3702"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Refactoring nested recursion into non-nested multi-recursion or linear recursion
is a non-trivial task and sometimes it may be impossible.&lt;/p&gt;
&lt;h2 id="triple-nested-recursion"&gt;&lt;a class="toclink" href="#triple-nested-recursion"&gt;Triple Nested Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The level of nesting is not limited to just two calls, the &lt;a href="https://mathworld.wolfram.com/HofstadterH-Sequence.html" target="_blank"&gt;Hofstadter H Sequence&lt;/a&gt;
has triple nesting recursion for example:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20hofstadter_h%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20return%20n%20-%20hofstadter_h%28%0A%20%20%20%20%20%20%20%20hofstadter_h%28%0A%20%20%20%20%20%20%20%20%20%20%20%20hofstadter_h%28n%20-%201%29%0A%20%20%20%20%20%20%20%20%29%0A%20%20%20%20%29%0A%0Aactual%20%3D%20%5Bhofstadter_h%28i%29%20for%20i%20in%20range%286%29%5D%0Aexpected%20%3D%20%5B0,%201,%201,%202,%203,%204%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hofstadter_h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;hofstadter_h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hofstadter_h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hofstadter_h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hofstadter_h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_hofstadter_h.png"&gt;&lt;img alt="Recursive Hofstadter H" class="b-lazy" data-src="/blog/images/recursion/recursive_hofstadter_h.png" src="https://elc.github.io/blog/images/recursion/recursive_hofstadter_h-thumbnail.png" width="9794"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="nested-recursion-with-more-than-one-argument"&gt;&lt;a class="toclink" href="#nested-recursion-with-more-than-one-argument"&gt;Nested Recursion with more than one argument&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some functions can have multiple arguments and be nested recursive. One example
is the &lt;a href="https://mathworld.wolfram.com/AckermannFunction.html" target="_blank"&gt;Ackermann
function&lt;/a&gt; grows extremely fast due to this nested recursive definition
and it is the simplest function proved not to be primitive recursive, meaning
that it cannot be expressed in iterative form with for loops.&lt;/p&gt;
&lt;p&gt;This function is currently used to test compilers' efficiency at handling really
deep recursive functions. This is a case of a nested recursive function that is
also tail recursive.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20ackermann%28m%3A%20int,%20n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20m%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20n%20%2B%201%0A%20%20%20%20if%20m%20%3E%200%20and%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20ackermann%28m%20-%201,%201%29%20%20%20%20%0A%20%20%20%20return%20ackermann%28m%20-%201,%20ackermann%28m,%20n%20-%201%29%29%0A%0Aactual%20%3D%20%5B%0A%20%20%20%20ackermann%28i,%20j%29%20%0A%20%20%20%20for%20i%20in%20range%283%29%20%0A%20%20%20%20for%20j%20in%20range%283%29%0A%5D%0Aexpected%20%3D%20%5B1,%202,%203,%202,%203,%204,%203,%205,%207%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ackermann&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ackermann&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ackermann&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ackermann&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ackermann&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_ackermann.png"&gt;&lt;img alt="Recursive Ackerman" class="b-lazy" data-src="/blog/images/recursion/recursive_ackermann.png" src="https://elc.github.io/blog/images/recursion/recursive_ackermann-thumbnail.png" width="6185"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="indirect-recursion"&gt;&lt;a class="toclink" href="#indirect-recursion"&gt;Indirect Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So far, all the examples showed functions that called themselves, this is direct
recursion. An alternative approach is indirect recursion, also known as mutual
recursion. In this case, the same categories could be applied (linear, tail,
head, nested, etc.), but the recursive call is now to another function, that
other function will, in turn, call the original one.&lt;/p&gt;
&lt;h2 id="mutual-linear-recursion"&gt;&lt;a class="toclink" href="#mutual-linear-recursion"&gt;Mutual Linear Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A simple example of mutual linear tail recursion is a set of functions that
determines if a number is odd or even:  &lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20is_even%28n%3A%20int%29%20-%3E%20bool%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20True%0A%20%20%20%20return%20is_odd%28n%20-%201%29%0A%0Adef%20is_odd%28n%3A%20int%29%20-%3E%20bool%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20False%0A%20%20%20%20return%20is_even%28n%20-%201%29%0A%0Aactual_even%20%3D%20%5Bis_even%28i%29%20for%20i%20in%20range%286%29%5D%0Aexpected_even%20%3D%20%5BTrue,%20False,%20True,%20False,%20True,%20False%5D%0Aassert%20actual_even%20%3D%3D%20expected_even%0A%0Aactual_odd%20%3D%20%5Bis_odd%28i%29%20for%20i%20in%20range%286%29%5D%0Aexpected_odd%20%3D%20%5BFalse,%20True,%20False,%20True,%20False,%20True%5D%0Aassert%20actual_odd%20%3D%3D%20expected_odd&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_even&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;is_odd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;is_odd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;is_even&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;is_even&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;is_odd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_is_even.png"&gt;&lt;img alt="Recursive Is Even" class="narrow b-lazy" data-src="/blog/images/recursion/recursive_is_even.png" src="https://elc.github.io/blog/images/recursion/recursive_is_even-thumbnail.png" width="200"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Of course, it is also possible to implement a function that computes the same in
a non-recursive form. However, this example does not require division or modulo
computation, it is much slower for big numbers.&lt;/p&gt;
&lt;h2 id="mutual-multi-recursion"&gt;&lt;a class="toclink" href="#mutual-multi-recursion"&gt;Mutual Multi Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Mutual recursion can also happen in multi-recursive functions. Take the
following direct multi-recursive function that computes the nth Lucas number:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20lucas%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%202%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20lucas%28n-1%29%20%2B%20lucas%28n-2%29%0A%0Aactual%20%3D%20%5Blucas%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B2,%201,%203,%204,%207,%2011,%2018%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_lucas.png"&gt;&lt;img alt="Recursive Lucas" class="b-lazy" data-src="/blog/images/recursion/recursive_lucas.png" src="https://elc.github.io/blog/images/recursion/recursive_lucas-thumbnail.png" width="2225"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It is possible to write both the Lucas and the Fibonacci functions in a mutual
recursive form:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20lucas%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%202%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20%28%0A%20%20%20%20%20%20%20%202%20*%20fibonacci%28n%29%0A%20%20%20%20%20%20%20%20-%20fibonacci%28n-1%29%0A%20%20%20%20%20%20%20%20%2B%20lucas%28n-2%29%0A%20%20%20%20%29%0A%0A%0Adef%20fibonacci%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20%28fibonacci%28n-1%29%20%2B%20lucas%28n-1%29%29%20//%202%0A%0Aactual_lucas%20%3D%20%5Blucas%28i%29%20for%20i%20in%20range%285%29%5D%0Aexpected_lucas%20%3D%20%5B2,%201,%203,%204,%207%5D%0Aassert%20actual_lucas%20%3D%3D%20expected_lucas%0A%0Aactual_fibonacci%20%3D%20%5Bfibonacci%28i%29%20for%20i%20in%20range%285%29%5D%0Aexpected_fibonacci%20%3D%20%5B0,%201,%201,%202,%203%5D%0Aassert%20actual_fibonacci%20%3D%3D%20expected_fibonacci&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/mutual_recursive_fibonacci.png"&gt;&lt;img alt="Mutual Recursive Fibonacci" class="b-lazy" data-src="/blog/images/recursion/mutual_recursive_fibonacci.png" src="https://elc.github.io/blog/images/recursion/mutual_recursive_fibonacci-thumbnail.png" width="5365"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This implementation is standalone and does not require any of the two functions
to be defined in a direct recursive way. In practical terms, there is no gain as
it makes the whole computation slower and less efficient, it is just for
demonstration purposes.&lt;/p&gt;
&lt;p&gt;Similarly, the sequence defined as the multiplication of the last two terms can
be implemented in a direct multi-recursive form:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20multiply_last_two%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%202%0A%20%20%20%20return%20%28%0A%20%20%20%20%20%20%20%20multiply_last_two%28n%20-%201%29%0A%20%20%20%20%20%20%20%20*%20multiply_last_two%28n%20-%202%29%0A%20%20%20%20%29%0A%0Aactual%20%3D%20%5Bmultiply_last_two%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B1,%202,%202,%204,%208,%2032,%20256%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;multiply_last_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;multiply_last_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;multiply_last_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;multiply_last_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_multiply_last_two.png"&gt;&lt;img alt="Mutual Recursive Fibonacci" class="b-lazy" data-src="/blog/images/recursion/recursive_multiply_last_two.png" src="https://elc.github.io/blog/images/recursion/recursive_multiply_last_two-thumbnail.png" width="3988"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This again can be used to implement the Fibonacci and the multiply last two as
mutually recursive functions.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=import%20math%0A%0Adef%20fibonacci%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20int%28%0A%20%20%20%20%20%20%20%20math.log2%28multiply_last_two%28n%20-%201%29%0A%20%20%20%20%20%20%20%20*%20multiply_last_two%28n%20-%202%29%0A%20%20%20%20%20%20%20%20%29%0A%20%20%20%20%29%0A%0Adef%20multiply_last_two%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%202%0A%20%20%20%20return%202%20**%20%28fibonacci%28n-1%29%20%2B%20fibonacci%28n-2%29%29%0A%0A%0Aactual_fibonacci%20%3D%20%5Bfibonacci%28i%29%20for%20i%20in%20range%285%29%5D%0Aexpected_fibonacci%20%3D%20%5B0,%201,%201,%202,%203%5D%0Aassert%20actual_fibonacci%20%3D%3D%20expected_fibonacci%0A%0Aactual%20%3D%20%5Bmultiply_last_two%28i%29%20for%20i%20in%20range%287%29%5D%0Aexpected%20%3D%20%5B1,%202,%202,%204,%208,%2032,%20256%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;math&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;multiply_last_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;multiply_last_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;multiply_last_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;multiply_last_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/mutual_recursive_fibonacci_alternative.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/mutual_recursive_fibonacci_alternative.png" src="https://elc.github.io/blog/images/recursion/mutual_recursive_fibonacci_alternative-thumbnail.png" width="3163"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="mutual-nested-recursion"&gt;&lt;a class="toclink" href="#mutual-nested-recursion"&gt;Mutual Nested Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Mutual recursion can also appear in a nested form, as is the case of the
&lt;a href="https://mathworld.wolfram.com/HofstadterMale-FemaleSequences.html#:~:text=are%201%2C%201%2C%202%2C,(OEIS%20A005378)." target="_blank"&gt;Hofstadter Female and Male sequences&lt;/a&gt; which are mutually nested recursive.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20hofstadter_f%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20n%20-%20hofstadter_m%28hofstadter_f%28n%20-%201%29%29%0A%0Adef%20hofstadter_m%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20return%20n%20-%20hofstadter_f%28hofstadter_m%28n%20-%201%29%29%0A%0Aactual_female%20%3D%20%5Bhofstadter_f%28i%29%20for%20i%20in%20range%286%29%5D%0Aexpected_female%20%3D%20%5B1,%201,%202,%202,%203,%203%5D%0Aassert%20actual_female%20%3D%3D%20expected_female%0A%0Aactual_male%20%3D%20%5Bhofstadter_m%28i%29%20for%20i%20in%20range%286%29%5D%0Aexpected_male%20%3D%20%5B0,%200,%201,%202,%202,%203%5D%0Aassert%20actual_male%20%3D%3D%20expected_male&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hofstadter_female&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;hofstadter_male&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hofstadter_female&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hofstadter_male&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;hofstadter_female&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hofstadter_male&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hofstadter_female&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;hofstadter_male&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/mutual_recursive_hofstadter_female.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/mutual_recursive_hofstadter_female.png" src="https://elc.github.io/blog/images/recursion/mutual_recursive_hofstadter_female-thumbnail.png" width="5290"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="mutual-triple-recursion"&gt;&lt;a class="toclink" href="#mutual-triple-recursion"&gt;Mutual Triple Recursion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Indirect recursion is not limited to only two functions, the following example
combines the Lucas, Fibonacci and multiply last two functions in a triple mutual
recursive form, where each function uses the other two and itself.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=import%20math%0A%0Adef%20lucas%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%202%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20%28%0A%20%20%20%20%20%20%20%202%20*%20math.log2%28multiply_last_two%28n%20-%201%29%20%0A%20%20%20%20%20%20%20%20*%20multiply_last_two%28n%20-%202%29%29%0A%20%20%20%20%20%20%20%20-%20fibonacci%28n-1%29%20%2B%20lucas%28n-2%29%0A%20%20%20%20%29%0A%0A%0Adef%20fibonacci%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20%28fibonacci%28n-1%29%20%2B%20lucas%28n-1%29%29%20//%202%0A%0A%0Adef%20multiply_last_two%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%202%0A%20%20%20%20return%202%20**%20%28%0A%20%20%20%20%20%20%20%201.5%20*%20fibonacci%28n-2%29%20%2B%200.5%20*%20lucas%28n-2%29%0A%20%20%20%20%29%0A%0A%0Aactual_lucas%20%3D%20%5Blucas%28i%29%20for%20i%20in%20range%285%29%5D%0Aexpected_lucas%20%3D%20%5B2,%201,%203,%204,%207%5D%0Aassert%20actual_lucas%20%3D%3D%20expected_lucas%0A%0Aactual_fibonacci%20%3D%20%5Bfibonacci%28i%29%20for%20i%20in%20range%285%29%5D%0Aexpected_fibonacci%20%3D%20%5B0,%201,%201,%202,%203%5D%0Aassert%20actual_fibonacci%20%3D%3D%20expected_fibonacci%0A%0Aactual%20%3D%20%5Bmultiply_last_two%28i%29%20for%20i%20in%20range%285%29%5D%0Aexpected%20%3D%20%5B1,%202,%202,%204,%208%5D%0Aassert%20actual%20%3D%3D%20expected&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;math&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;multiply_last_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;multiply_last_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;multiply_last_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lucas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;multiply_last_two&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/mutual_triple_recursive_fibonacci.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/mutual_triple_recursive_fibonacci.png" src="https://elc.github.io/blog/images/recursion/mutual_triple_recursive_fibonacci-thumbnail.png" width="6969"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="recursion-related-techniques"&gt;&lt;a class="toclink" href="#recursion-related-techniques"&gt;Recursion related techniques&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Recursion is a wide field, and due to language, compilers and general developer
experience limitations, several tools and techniques have been developed to
improve recursion support and performance.&lt;/p&gt;
&lt;h2 id="memoization"&gt;&lt;a class="toclink" href="#memoization"&gt;Memoization&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When dealing with recursive functions, it is important to keep track of the call
stack and optimize it to avoid wasting resources. Many recursive functions call
themselves multiple times with the same parameters in their call graph, these
repeated calls can be cached (assuming the function is pure) to avoid (1)
continuing traversing a recursive tree unnecessarily and (2) returning the
result in constant time. This technique of caching previously computed results
is called &lt;a href="https://en.wikipedia.org/wiki/Memoization" target="_blank"&gt;&lt;strong&gt;memoization&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Memoization is easy to implement in Python, both from scratch and using the
standard library. &lt;/p&gt;
&lt;p&gt;The from-scratch implementation can be written using decorators:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wraps&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ParamSpec&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;T&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;P&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ParamSpec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;P&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="nd"&gt;@wraps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;wrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;P&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;nonlocal&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;

        &lt;span class="n"&gt;cacheable_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;())))&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cacheable_args&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cacheable_args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;cacheable_args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;wrapper&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Another possibility is to use the standard library, which has support for
memoization through &lt;code&gt;functools.cache&lt;/code&gt;, this function is available in Python 3.9
or later. For older versions, it is also possible to use &lt;code&gt;functools.lru_cache&lt;/code&gt;,
which also adds the capability of setting a max limit of cached entries.&lt;/p&gt;
&lt;h2 id="memoization-examples"&gt;&lt;a class="toclink" href="#memoization-examples"&gt;Memoization Examples&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This section will show what the call graph of the above examples looks like when
memoization is applied.&lt;/p&gt;
&lt;p&gt;Take for example the following call graph for a multi-recursive implementation
of &lt;code&gt;fibonacci(5)&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_non_memoized_fibonacci.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/recursive_non_memoized_fibonacci.png" src="https://elc.github.io/blog/images/recursion/recursive_non_memoized_fibonacci-thumbnail.png" width="4106"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When using memoization the total number of calls is reduced significantly (from
15 calls to 9):&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20functools%20import%20wraps%0Afrom%20typing%20import%20Callable,%20TypeVar,%20Any%0A%0AT%20%3D%20TypeVar%28%22T%22%29%0A%0A%23%20With%20Scratch%20Implementation%0Adef%20memoize%28function%3A%20Callable%5B...,%20T%5D%29%20-%3E%20Callable%5B...,%20T%5D%3A%0A%20%20%20%20cache%3A%20dict%5Bstr,%20T%5D%20%3D%20%7B%7D%0A%0A%20%20%20%20%40wraps%28function%29%0A%20%20%20%20def%20wrapper%28*args,%20**kwargs%29%20-%3E%20T%3A%0A%20%20%20%20%20%20%20%20nonlocal%20cache%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20cacheable_args%20%3D%20str%28tuple%28sorted%28args%29%29%20%2B%20tuple%28sorted%28kwargs.items%28%29%29%29%29%0A%20%20%20%20%20%20%20%20if%20cacheable_args%20not%20in%20cache%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20cache%5Bcacheable_args%5D%20%3D%20function%28*args,%20**kwargs%29%0A%20%20%20%20%20%20%20%20return%20cache%5Bcacheable_args%5D%0A%0A%20%20%20%20return%20wrapper%0A%0A%40memoize%0Adef%20fibonacci_memoize%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20fibonacci_memoize%28n-1%29%20%2B%20fibonacci_memoize%28n-2%29%0A%0Aassert%20fibonacci_memoize%285%29%20%3D%3D%205%0Aassert%20fibonacci_memoize%285%29%20%3D%3D%205%0A%0A%0A%23%20With%20Functools%20Implementation%0Afrom%20functools%20import%20lru_cache%0A%0A%40lru_cache%28maxsize%3DNone%29%0Adef%20fibonacci_lru%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20fibonacci_lru%28n-1%29%20%2B%20fibonacci_lru%28n-2%29%0A%0Aassert%20fibonacci_lru%285%29%20%3D%3D%205%0Aassert%20fibonacci_lru%285%29%20%3D%3D%205%0A&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_memoized_fibonacci.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/recursive_memoized_fibonacci.png" src="https://elc.github.io/blog/images/recursion/recursive_memoized_fibonacci-thumbnail.png" width="2125"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Depending on the implementation, the effect of memoization is similar to
&lt;em&gt;linearizing&lt;/em&gt; the multi-recursive function, as the tree has much fewer branches
while the depth is kept the same.&lt;/p&gt;
&lt;p&gt;If considering the Fibonacci Fast Doubles implementation of &lt;code&gt;fibonacci(10)&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/non_memoized_fast_double_fibonacci.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/non_memoized_fast_double_fibonacci.png" src="https://elc.github.io/blog/images/recursion/non_memoized_fast_double_fibonacci-thumbnail.png" width="4106"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This can also be reduced (from 15 calls to 11):&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20functools%20import%20wraps%0Afrom%20typing%20import%20Callable,%20TypeVar,%20Any%0A%0AT%20%3D%20TypeVar%28%22T%22%29%0A%0A%23%20With%20Scratch%20Implementation%0Adef%20memoize%28function%3A%20Callable%5B...,%20T%5D%29%20-%3E%20Callable%5B...,%20T%5D%3A%0A%20%20%20%20cache%3A%20dict%5Bstr,%20T%5D%20%3D%20%7B%7D%0A%0A%20%20%20%20%40wraps%28function%29%0A%20%20%20%20def%20wrapper%28*args,%20**kwargs%29%20-%3E%20T%3A%0A%20%20%20%20%20%20%20%20nonlocal%20cache%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20cacheable_args%20%3D%20str%28tuple%28sorted%28args%29%29%20%2B%20tuple%28sorted%28kwargs.items%28%29%29%29%29%0A%20%20%20%20%20%20%20%20if%20cacheable_args%20not%20in%20cache%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20cache%5Bcacheable_args%5D%20%3D%20function%28*args,%20**kwargs%29%0A%20%20%20%20%20%20%20%20return%20cache%5Bcacheable_args%5D%0A%0A%20%20%20%20return%20wrapper%0A%0A%0A%40memoize%0Adef%20fibonacci_memoize%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%23%20Fast%20Doubling%20Method%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20%0A%20%20%20%20is_odd%20%3D%20n%20%25%202%0A%20%20%20%20m%20%3D%20n%20//%202%20%2B%20is_odd%0A%20%20%20%20fib_m%20%3D%20fibonacci_memoize%28m%29%0A%20%20%20%20fib_m_1%20%3D%20fibonacci_memoize%28m%20-%201%29%0A%0A%20%20%20%20if%20is_odd%3A%0A%20%20%20%20%20%20%20%20return%20fib_m_1%20**%202%20%2B%20fib_m%20**%202%0A%20%20%20%20return%202%20*%20fib_m%20*%20fib_m_1%20%2B%20fib_m%20**%202%0A%0Aassert%20fibonacci_memoize%285%29%20%3D%3D%205%0Aassert%20fibonacci_memoize%285%29%20%3D%3D%205%0A%0A%0A%23%20With%20Functools%20Implementation%0Afrom%20functools%20import%20lru_cache%0A%0A%40lru_cache%28maxsize%3DNone%29%0Adef%20fibonacci_lru%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20%23%20Fast%20Doubling%20Method%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20%0A%20%20%20%20is_odd%20%3D%20n%20%25%202%0A%20%20%20%20m%20%3D%20n%20//%202%20%2B%20is_odd%0A%20%20%20%20fib_m%20%3D%20fibonacci_lru%28m%29%0A%20%20%20%20fib_m_1%20%3D%20fibonacci_lru%28m%20-%201%29%0A%0A%20%20%20%20if%20is_odd%3A%0A%20%20%20%20%20%20%20%20return%20fib_m_1%20**%202%20%2B%20fib_m%20**%202%0A%20%20%20%20return%202%20*%20fib_m%20*%20fib_m_1%20%2B%20fib_m%20**%202%0A%0Aassert%20fibonacci_lru%285%29%20%3D%3D%205%0Aassert%20fibonacci_lru%285%29%20%3D%3D%205%0A&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/memoized_fast_double_fibonacci.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/memoized_fast_double_fibonacci.png" src="https://elc.github.io/blog/images/recursion/memoized_fast_double_fibonacci-thumbnail.png" width="2125"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Memoization can also be applied to nested recursive functions such as the
&lt;code&gt;hofstadter_g(4)&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/non_memoized_hofstadter_g.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/non_memoized_hofstadter_g.png" src="https://elc.github.io/blog/images/recursion/non_memoized_hofstadter_g-thumbnail.png" width="4106"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now memoized (from 19 calls to 9):&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20functools%20import%20wraps%0Afrom%20typing%20import%20Callable,%20TypeVar,%20Any%0A%0AT%20%3D%20TypeVar%28%22T%22%29%0A%0A%23%20With%20Scratch%20Implementation%0Adef%20memoize%28function%3A%20Callable%5B...,%20T%5D%29%20-%3E%20Callable%5B...,%20T%5D%3A%0A%20%20%20%20cache%3A%20dict%5Bstr,%20T%5D%20%3D%20%7B%7D%0A%0A%20%20%20%20%40wraps%28function%29%0A%20%20%20%20def%20wrapper%28*args,%20**kwargs%29%20-%3E%20T%3A%0A%20%20%20%20%20%20%20%20nonlocal%20cache%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20cacheable_args%20%3D%20str%28tuple%28sorted%28args%29%29%20%2B%20tuple%28sorted%28kwargs.items%28%29%29%29%29%0A%20%20%20%20%20%20%20%20if%20cacheable_args%20not%20in%20cache%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20cache%5Bcacheable_args%5D%20%3D%20function%28*args,%20**kwargs%29%0A%20%20%20%20%20%20%20%20return%20cache%5Bcacheable_args%5D%0A%0A%20%20%20%20return%20wrapper%0A%0A%0A%40memoize%0Adef%20hofstadter_g_memoize%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20return%20n%20-%20hofstadter_g_memoize%28hofstadter_g_memoize%28n%20-%201%29%29%0A%0Aassert%20hofstadter_g_memoize%285%29%20%3D%3D%203%0Aassert%20hofstadter_g_memoize%285%29%20%3D%3D%203%0A%0A%0A%23%20With%20Functools%20Implementation%0Afrom%20functools%20import%20lru_cache%0A%0A%40lru_cache%28maxsize%3DNone%29%0Adef%20hofstadter_g_lru%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20return%20n%20-%20hofstadter_g_lru%28hofstadter_g_lru%28n%20-%201%29%29%0A%0Aassert%20hofstadter_g_lru%285%29%20%3D%3D%203%0Aassert%20hofstadter_g_lru%285%29%20%3D%3D%203%0A&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/memoized_hofstadter_g.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/memoized_hofstadter_g.png" src="https://elc.github.io/blog/images/recursion/memoized_hofstadter_g-thumbnail.png" width="2125"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Or deeply nested recursive functions like the &lt;code&gt;hofstadter_h(3)&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_hofstadter_h.png"&gt;&lt;img alt="Recursive Hofstadter H" class="b-lazy" data-src="/blog/images/recursion/recursive_hofstadter_h.png" src="https://elc.github.io/blog/images/recursion/recursive_hofstadter_h-thumbnail.png" width="9794"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And now memoized (from 22 to 10 calls)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20functools%20import%20wraps%0Afrom%20typing%20import%20Callable,%20TypeVar,%20Any%0A%0AT%20%3D%20TypeVar%28%22T%22%29%0A%0A%23%20With%20Scratch%20Implementation%0Adef%20memoize%28function%3A%20Callable%5B...,%20T%5D%29%20-%3E%20Callable%5B...,%20T%5D%3A%0A%20%20%20%20cache%3A%20dict%5Bstr,%20T%5D%20%3D%20%7B%7D%0A%0A%20%20%20%20%40wraps%28function%29%0A%20%20%20%20def%20wrapper%28*args,%20**kwargs%29%20-%3E%20T%3A%0A%20%20%20%20%20%20%20%20nonlocal%20cache%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20cacheable_args%20%3D%20str%28tuple%28sorted%28args%29%29%20%2B%20tuple%28sorted%28kwargs.items%28%29%29%29%29%0A%20%20%20%20%20%20%20%20if%20cacheable_args%20not%20in%20cache%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20cache%5Bcacheable_args%5D%20%3D%20function%28*args,%20**kwargs%29%0A%20%20%20%20%20%20%20%20return%20cache%5Bcacheable_args%5D%0A%0A%20%20%20%20return%20wrapper%0A%0A%0A%40memoize%0Adef%20hofstadter_h_memoize%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20return%20n%20-%20hofstadter_h_memoize%28hofstadter_h_memoize%28hofstadter_h_memoize%28n%20-%201%29%29%29%0A%0Aassert%20hofstadter_h_memoize%285%29%20%3D%3D%204%0Aassert%20hofstadter_h_memoize%285%29%20%3D%3D%204%0A%0A%0A%23%20With%20Functools%20Implementation%0Afrom%20functools%20import%20lru_cache%0A%0A%40lru_cache%28maxsize%3DNone%29%0Adef%20hofstadter_h_lru%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20return%20n%20-%20hofstadter_h_lru%28hofstadter_h_lru%28hofstadter_h_lru%28n%20-%201%29%29%29%0A%0Aassert%20hofstadter_h_lru%285%29%20%3D%3D%204%0Aassert%20hofstadter_h_lru%285%29%20%3D%3D%204%0A&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/memoized_hofstadter_h.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/memoized_hofstadter_h.png" src="https://elc.github.io/blog/images/recursion/memoized_hofstadter_h-thumbnail.png" width="2125"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The same applies to more complex functions like the Ackermann function with
&lt;code&gt;Ackermann(2, 3)&lt;/code&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/recursive_ackermann.png"&gt;&lt;img alt="Recursive Ackerman" class="b-lazy" data-src="/blog/images/recursion/recursive_ackermann.png" src="https://elc.github.io/blog/images/recursion/recursive_ackermann-thumbnail.png" width="6185"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And now memoized (from 44 calls to 23):&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20functools%20import%20wraps%0Afrom%20typing%20import%20Callable,%20TypeVar,%20Any%0A%0AT%20%3D%20TypeVar%28%22T%22%29%0A%0A%23%20With%20Scratch%20Implementation%0Adef%20memoize%28function%3A%20Callable%5B...,%20T%5D%29%20-%3E%20Callable%5B...,%20T%5D%3A%0A%20%20%20%20cache%3A%20dict%5Bstr,%20T%5D%20%3D%20%7B%7D%0A%0A%20%20%20%20%40wraps%28function%29%0A%20%20%20%20def%20wrapper%28*args,%20**kwargs%29%20-%3E%20T%3A%0A%20%20%20%20%20%20%20%20nonlocal%20cache%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20cacheable_args%20%3D%20str%28tuple%28sorted%28args%29%29%20%2B%20tuple%28sorted%28kwargs.items%28%29%29%29%29%0A%20%20%20%20%20%20%20%20if%20cacheable_args%20not%20in%20cache%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20cache%5Bcacheable_args%5D%20%3D%20function%28*args,%20**kwargs%29%0A%20%20%20%20%20%20%20%20return%20cache%5Bcacheable_args%5D%0A%0A%20%20%20%20return%20wrapper%0A%0A%0A%40memoize%0Adef%20ackermann_memoize%28m%3A%20int,%20n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20m%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20n%20%2B%201%0A%20%20%20%20if%20m%20%3E%200%20and%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20ackermann_memoize%28m%20-%201,%201%29%20%20%20%20%0A%20%20%20%20return%20ackermann_memoize%28m%20-%201,%20ackermann_memoize%28m,%20n%20-%201%29%29%0A%0Aassert%20ackermann_memoize%282,%202%29%20%3D%3D%207%0Aassert%20ackermann_memoize%282,%202%29%20%3D%3D%207%0A%0A%0A%23%20With%20Functools%20Implementation%0Afrom%20functools%20import%20lru_cache%0A%0A%40lru_cache%28maxsize%3DNone%29%0Adef%20ackermann_lru%28m%3A%20int,%20n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20m%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20n%20%2B%201%0A%20%20%20%20if%20m%20%3E%200%20and%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20ackermann_lru%28m%20-%201,%201%29%20%20%20%20%0A%20%20%20%20return%20ackermann_lru%28m%20-%201,%20ackermann_lru%28m,%20n%20-%201%29%29%0A%0Aassert%20ackermann_lru%282,%202%29%20%3D%3D%207%0Aassert%20ackermann_lru%282,%202%29%20%3D%3D%207%0A&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/memoized_ackermann.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/memoized_ackermann.png" src="https://elc.github.io/blog/images/recursion/memoized_ackermann-thumbnail.png" width="2125"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Memoization can also be used for mutual recursive functions, the following
examples show the mutual fibonacci-lucas recursion and  the Hofstadter
female-male&lt;/p&gt;
&lt;p&gt;Multi recursive fibonacci-lucas:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/mutual_recursive_fibonacci.png"&gt;&lt;img alt="Mutual Recursive Fibonacci" class="b-lazy" data-src="/blog/images/recursion/mutual_recursive_fibonacci.png" src="https://elc.github.io/blog/images/recursion/mutual_recursive_fibonacci-thumbnail.png" width="5365"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And now memoized (from 26 to 13):&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20functools%20import%20wraps%0Afrom%20typing%20import%20Callable,%20TypeVar,%20Any%0A%0AT%20%3D%20TypeVar%28%22T%22%29%0A%0A%23%20With%20Scratch%20Implementation%0Adef%20memoize%28function%3A%20Callable%5B...,%20T%5D%29%20-%3E%20Callable%5B...,%20T%5D%3A%0A%20%20%20%20cache%3A%20dict%5Bstr,%20T%5D%20%3D%20%7B%7D%0A%0A%20%20%20%20%40wraps%28function%29%0A%20%20%20%20def%20wrapper%28*args,%20**kwargs%29%20-%3E%20T%3A%0A%20%20%20%20%20%20%20%20nonlocal%20cache%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20cacheable_args%20%3D%20str%28tuple%28sorted%28args%29%29%20%2B%20tuple%28sorted%28kwargs.items%28%29%29%29%29%0A%20%20%20%20%20%20%20%20if%20cacheable_args%20not%20in%20cache%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20cache%5Bcacheable_args%5D%20%3D%20function%28*args,%20**kwargs%29%0A%20%20%20%20%20%20%20%20return%20cache%5Bcacheable_args%5D%0A%0A%20%20%20%20return%20wrapper%0A%0A%0A%40memoize%0Adef%20lucas_memoize%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%202%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%202%20*%20fibonacci_memoize%28n%29%20-%20fibonacci_memoize%28n-1%29%20%2B%20lucas_memoize%28n-2%29%0A%0A%40memoize%0Adef%20fibonacci_memoize%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20%28fibonacci_memoize%28n-1%29%20%2B%20lucas_memoize%28n-1%29%29%20//%202%0A%0Aassert%20lucas_memoize%284%29%20%3D%3D%207%0Aassert%20lucas_memoize%284%29%20%3D%3D%207%0Aassert%20fibonacci_memoize%284%29%20%3D%3D%203%0Aassert%20fibonacci_memoize%284%29%20%3D%3D%203%0A%0A%0A%23%20With%20Functools%20Implementation%0Afrom%20functools%20import%20lru_cache%0A%0A%40lru_cache%28maxsize%3DNone%29%0Adef%20lucas_lru%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%202%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%202%20*%20fibonacci_lru%28n%29%20-%20fibonacci_lru%28n-1%29%20%2B%20lucas_lru%28n-2%29%0A%0A%40lru_cache%28maxsize%3DNone%29%0Adef%20fibonacci_lru%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20%28fibonacci_lru%28n-1%29%20%2B%20lucas_lru%28n-1%29%29%20//%202%0A%0Aassert%20lucas_lru%284%29%20%3D%3D%207%0Aassert%20lucas_lru%284%29%20%3D%3D%207%0Aassert%20fibonacci_lru%284%29%20%3D%3D%203%0Aassert%20fibonacci_lru%284%29%20%3D%3D%203%0A&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/memoized_mutual_recursive_fibonacci.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/memoized_mutual_recursive_fibonacci.png" src="https://elc.github.io/blog/images/recursion/memoized_mutual_recursive_fibonacci-thumbnail.png" width="2125"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And the hofstadter female-male recursion:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/mutual_recursive_hofstadter_female.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/mutual_recursive_hofstadter_female.png" src="https://elc.github.io/blog/images/recursion/mutual_recursive_hofstadter_female-thumbnail.png" width="5290"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And now memoized (from 15 to 11 calls)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20functools%20import%20wraps%0Afrom%20typing%20import%20Callable,%20TypeVar,%20Any%0A%0AT%20%3D%20TypeVar%28%22T%22%29%0A%0A%23%20With%20Scratch%20Implementation%0Adef%20memoize%28function%3A%20Callable%5B...,%20T%5D%29%20-%3E%20Callable%5B...,%20T%5D%3A%0A%20%20%20%20cache%3A%20dict%5Bstr,%20T%5D%20%3D%20%7B%7D%0A%0A%20%20%20%20%40wraps%28function%29%0A%20%20%20%20def%20wrapper%28*args,%20**kwargs%29%20-%3E%20T%3A%0A%20%20%20%20%20%20%20%20nonlocal%20cache%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20cacheable_args%20%3D%20str%28tuple%28sorted%28args%29%29%20%2B%20tuple%28sorted%28kwargs.items%28%29%29%29%29%0A%20%20%20%20%20%20%20%20if%20cacheable_args%20not%20in%20cache%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20cache%5Bcacheable_args%5D%20%3D%20function%28*args,%20**kwargs%29%0A%20%20%20%20%20%20%20%20return%20cache%5Bcacheable_args%5D%0A%0A%20%20%20%20return%20wrapper%0A%0A%0A%40memoize%0Adef%20hofstadter_female_memoize%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20n%20-%20hofstadter_male_memoize%28hofstadter_female_memoize%28n%20-%201%29%29%0A%0A%40memoize%0Adef%20hofstadter_male_memoize%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20return%20n%20-%20hofstadter_female_memoize%28hofstadter_male_memoize%28n%20-%201%29%29%0A%0Aassert%20hofstadter_female_memoize%284%29%20%3D%3D%203%0Aassert%20hofstadter_female_memoize%284%29%20%3D%3D%203%0Aassert%20hofstadter_male_memoize%284%29%20%3D%3D%202%0Aassert%20hofstadter_male_memoize%284%29%20%3D%3D%202%0A%0A%0A%23%20With%20Functools%20Implementation%0Afrom%20functools%20import%20lru_cache%0A%0A%40lru_cache%28maxsize%3DNone%29%0Adef%20hofstadter_female_lru%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%201%0A%20%20%20%20return%20n%20-%20hofstadter_male_lru%28hofstadter_female_lru%28n%20-%201%29%29%0A%0A%40lru_cache%28maxsize%3DNone%29%0Adef%20hofstadter_male_lru%28n%3A%20int%29%20-%3E%20int%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20return%20n%20-%20hofstadter_female_lru%28hofstadter_male_lru%28n%20-%201%29%29%0A%0Aassert%20hofstadter_female_memoize%284%29%20%3D%3D%203%0Aassert%20hofstadter_female_memoize%284%29%20%3D%3D%203%0Aassert%20hofstadter_male_memoize%284%29%20%3D%3D%202%0Aassert%20hofstadter_male_memoize%284%29%20%3D%3D%202%0A&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/recursion/memoized_hofstadter_female.png"&gt;&lt;img alt="Mutual Recursive Fibonacci Alternative" class="b-lazy" data-src="/blog/images/recursion/memoized_hofstadter_female.png" src="https://elc.github.io/blog/images/recursion/memoized_hofstadter_female-thumbnail.png" width="2125"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Taking the &lt;code&gt;fibonacci(100)&lt;/code&gt; example from the previous section, when
incorporating the memoized approach the results change substantially:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Typical Multi Recursive Implementation: 1,146,295,688,027,634,168,203 calls ≈
  1 sextillion calls&lt;/li&gt;
&lt;li&gt;Memoized Typical Multi-Recursive Implementation: 199 calls
  (0.00000000000000002% of the original)&lt;/li&gt;
&lt;li&gt;Fast Doubles: 163 calls&lt;/li&gt;
&lt;li&gt;Tail Recursive Implementation (Memoization has no effect): 100 calls&lt;/li&gt;
&lt;li&gt;Memoized Fast Doubles: 29 calls (17.79% of the original)&lt;/li&gt;
&lt;li&gt;Linear Recursive Implementation (Memoization has no effect): 8 calls&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since the tail recursive and the linear recursive implementation do not have
repeated calls, memoization has no effect.&lt;/p&gt;
&lt;h2 id="trampolining"&gt;&lt;a class="toclink" href="#trampolining"&gt;Trampolining&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another restriction that many languages (such as Python) have is call stack
overflow, this happens when there are too many recursive calls in the call
stack. It is possible with minimal modifications to the original functions to
surpass this limitation and make the language treat the recursive function as an
iteration and thus bypass the overflow. This technique is called
&lt;a href="https://en.wikipedia.org/wiki/Trampoline_(computing)" target="_blank"&gt;&lt;strong&gt;trampoline&lt;/strong&gt;&lt;/a&gt; and requires the function to be implemented in
&lt;strong&gt;tail-recursive&lt;/strong&gt; form.&lt;/p&gt;
&lt;p&gt;Moreover, the function should &lt;strong&gt;defer the evaluation&lt;/strong&gt; of the tail call by using
an anonymous function (in Python called &lt;code&gt;lambda&lt;/code&gt;s). This step is needed to
simulate a lazy evaluation.&lt;/p&gt;
&lt;p&gt;The following is an example of how to implement the tail recursive Fibonacci
using trampolining for &lt;code&gt;fibonacci(10000)&lt;/code&gt; which would normally cause
&lt;a href="https://docs.python.org/3/library/exceptions.html#RecursionError" target="_blank"&gt;&lt;code&gt;RecursionError&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20trampoline%28function_or_result%29%3A%0A%20%20%20%20if%20not%20callable%28function_or_result%29%3A%0A%20%20%20%20%20%20%20%20return%20function_or_result%0A%0A%20%20%20%20while%20callable%28function_or_result%29%3A%0A%20%20%20%20%20%20%20%20function_or_result%20%3D%20function_or_result%28%29%0A%0A%20%20%20%20return%20function_or_result%0A%0A%0Adef%20fibonacci%28%0A%20%20%20%20n%3A%20int,%20partial_result%3A%20int%20%3D%200,%20result%3A%20int%20%3D%201%0A%29%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%20result%0A%0A%20%20%20%20return%20lambda%3A%20fibonacci%28n%20-%201,%20result,%20partial_result%20%2B%20result%29%0A%0A%0Aassert%20trampoline%28fibonacci%2830%29%29%20%3D%3D%20832040&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeAlias&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;T&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;TrampolineFunction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TypeAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Callable[[], T | TrampolineFunction[T]]&amp;quot;&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;trampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function_or_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;TrampolineFunction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function_or_result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;function_or_result&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function_or_result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;function_or_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;function_or_result&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;function_or_result&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;partial_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;TrampolineFunction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;partial_result&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;3364476487&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This way of programming has several similarities with the &lt;a href="https://en.wikipedia.org/wiki/Continuation-passing_style" target="_blank"&gt;continuation passing
style&lt;/a&gt;
since instead of executing the command, the function defers the execution to
another function which in the end runs the command. In Object Oriented
Programming similar behavior could have been achieved using the &lt;a href="https://en.wikipedia.org/wiki/Command_pattern" target="_blank"&gt;Command
Pattern&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This particular implementation has a significant drawback, it hinders debugging
and makes it less transparent, as can be seen in the run step-by-step example.
This is the reason why the author of Python &lt;a href="http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html" target="_blank"&gt;rejected the
proposal&lt;/a&gt;
to incorporate tail call optimization into the language.&lt;/p&gt;
&lt;p&gt;The implementation above using &lt;code&gt;lambda&lt;/code&gt;s is typical of other languages like
Javascript. In Python, it is possible to implement it in a different way
following &lt;a href="http://neopythonic.blogspot.com/2009/04/final-words-on-tail-calls.html" target="_blank"&gt;Guido's
approach&lt;/a&gt;
which makes debugging easier and less cryptic. On the other hand, types become a
bit more convoluted.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=def%20trampoline%28function,%20args%29%3A%0A%20%20%20%20result%20%3D%20function%28*args%29%0A%0A%20%20%20%20while%20hasattr%28result,%20%22__iter__%22%29%3A%0A%20%20%20%20%20%20%20%20function,%20args%20%3D%20result%0A%20%20%20%20%20%20%20%20result%20%3D%20function%28*args%29%0A%0A%20%20%20%20return%20result%0A%0Adef%20fibonacci%28%0A%20%20%20%20n%3A%20int,%20partial_result%3A%20int%20%3D%200,%20result%3A%20int%20%3D%201%0A%29%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%20result%0A%20%20%20%20%0A%20%20%20%20args%20%3D%20%28n-1,%20result,%20partial_result%20%2B%20result%29%0A%20%20%20%20return%20fibonacci,%20args%0A%0Aassert%20trampoline%28fibonacci,%20%2830,%20%29%29%20%3D%3D%20832040&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=edit&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeAlias&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;T&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;TrampolineFunction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TypeAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Callable[..., T | TrampolineResult[T] | T]&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;TrampolineArgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;TrampolineResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TypeAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tuple[TrampolineFunction[T], TrampolineArgs[T]]&amp;quot;&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;trampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TrampolineFunction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TrampolineArgs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Iterable&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;TrampolineResult[T]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;partial_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;TrampolineFunction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;partial_result&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,)))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;3364476487&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A combination of the previous two approaches can also be achieved by using
&lt;a href="https://en.wikipedia.org/wiki/Partial_evaluation?oldformat=true" target="_blank"&gt;partial
evaluation&lt;/a&gt;
through &lt;code&gt;functools.partial&lt;/code&gt;. This way, the code is simpler and more similar to
what one could find in other languages while still being easy to debug:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://pythontutor.com/visualize.html#code=from%20functools%20import%20partial%0A%0Adef%20trampoline%28function_or_result%29%3A%0A%20%20%20%20if%20not%20callable%28function_or_result%29%3A%0A%20%20%20%20%20%20%20%20return%20function_or_result%0A%0A%20%20%20%20while%20callable%28function_or_result%29%3A%0A%20%20%20%20%20%20%20%20function_or_result%20%3D%20function_or_result%28%29%0A%0A%20%20%20%20return%20function_or_result%0A%0Adef%20fibonacci%28%0A%20%20%20%20n%3A%20int,%20partial_result%3A%20int%20%3D%200,%20result%3A%20int%20%3D%201%0A%29%3A%0A%20%20%20%20if%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%200%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%20result%0A%0A%20%20%20%20return%20partial%28%0A%20%20%20%20%20%20%20%20fibonacci,%0A%20%20%20%20%20%20%20%20n%3Dn%20-%201,%0A%20%20%20%20%20%20%20%20partial_result%3Dresult,%0A%20%20%20%20%20%20%20%20result%3Dpartial_result%20%2B%20result%0A%20%20%20%20%29%0A%0Aassert%20trampoline%28fibonacci%2830%29%29%20%3D%3D%20832040&amp;amp;cumulative=false&amp;amp;heapPrimitives=nevernest&amp;amp;mode=display&amp;amp;origin=opt-frontend.js&amp;amp;py=3&amp;amp;rawInputLstJSON=%5B%5D&amp;amp;textReferences=false" target="_blank"&gt;Run Step by Step Online&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;annotations&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;functools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;partial&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Callable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TypeAlias&lt;/span&gt;

&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TypeVar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;T&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;TrampolineFunction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TypeAlias&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Callable[[], T | TrampolineFunction[T]]&amp;quot;&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;trampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;TrampolineFunction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;callable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;partial_result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;TrampolineFunction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;partial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;partial_result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;partial_result&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trampoline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fibonacci&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;3364476487&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Trampolines allow to convert of recursive function calls into iterations. There
is no built-in support like with the memoized technique and due to technical
limitations, it is not possible to implement them as decorators, which would
reduce the changes needed on the original function. The different
implementations shown should give a grasp of what is possible and how it could
be applied to other functions.&lt;/p&gt;
&lt;p&gt;It is also possible to modify the default configuration of the interpreter to
allow deeper recursions though. This can be done by setting a higher value to
the
&lt;a href="https://docs.python.org/3/library/sys.html#sys.setrecursionlimit" target="_blank"&gt;&lt;code&gt;sys.setrecursionlimit&lt;/code&gt;&lt;/a&gt;.
This method requires however access to the &lt;code&gt;sys&lt;/code&gt; module which may not be always
available or editable.&lt;/p&gt;
&lt;h2 id="call-by-need"&gt;&lt;a class="toclink" href="#call-by-need"&gt;Call-By-Need&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some programming languages execute instructions following a &lt;a href="https://en.wikipedia.org/wiki/Evaluation_strategy#Non-strict_binding_strategies" target="_blank"&gt;non-strict binding
strategy&lt;/a&gt;, that is, the parameters of a function are not evaluated before
the function is called. One such strategy is called
&lt;a href="https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_need"&gt;call-by-need&lt;/a&gt;,
which only evaluates the parameters when needed in the body of the function and
caches them in case they are re-used.&lt;/p&gt;
&lt;p&gt;When using recursive functions in languages that support call-by-need (like
Haskell or R), the execution could be optimized as only a subset of all the
recursive calls might be evaluated, thus reducing the cost of recursive
functions.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Recursion is a diverse topic that can be used as leverage to overcome
challenging problems, improve readability and facilitate the use of recursive
data structures. In Python, it is possible to use recursion with some
limitations, those could be mitigated by using memoization or trampolines. Other
languages may use different strategies such as call-by-need or tail-call
optimization.&lt;/p&gt;
&lt;p&gt;Every program written in iterative form can be rewritten in recursive form, it
is a good exercise to practice and gain intuition about recursion and when it
can be applied.&lt;/p&gt;
&lt;p&gt;In the end, recursion is another tool, it can be used everywhere but that is not
necessarily the best decision always, analyzing the context and the
cost-benefits is important.&lt;/p&gt;
&lt;p&gt;If recursion is the way to go, aim for tail recursion if possible or to leverage
memoization.&lt;/p&gt;
&lt;p&gt;Some challenges for the reader to practice recursion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write a function that determines if a number is prime&lt;/li&gt;
&lt;li&gt;Write the addition, multiplication and exponentiation functions&lt;/li&gt;
&lt;li&gt;Write a function that computes a running average of a sequence of numbers&lt;/li&gt;
&lt;/ul&gt;</content><category term="Programming"></category><category term="Python"></category><category term="Functional Programming"></category></entry><entry><title>Add Google Analytics (or any custom HTML) to Streamlit with Github Pages</title><link href="https://elc.github.io/posts/streamlit-google-analytics" rel="alternate"></link><published>2022-01-14T00:00:00-03:00</published><updated>2022-01-14T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2022-01-14:/posts/streamlit-google-analytics</id><summary type="html">&lt;p&gt;&lt;a href="/blog/images/streamlit-google-analytics/streamlit-google-analytics_headerimage.png"&gt;&lt;img alt="Jupyter Publishing Header Image" class="b-lazy" data-src="/blog/images/streamlit-google-analytics/streamlit-google-analytics_headerimage.png" src="https://elc.github.io/blog/images/streamlit-google-analytics/streamlit-google-analytics_headerimage-thumbnail.png" width="1444"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Streamlit is one of the most popular libraries for creating web apps using
Python, and they also provide 
&lt;a href="https://share.streamlit.io/" target="_blank"&gt;a service&lt;/a&gt; to freely host and
share your apps. One of the issues with this free sharing capability is that
one losses control over the app, for instance, it is no longer …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="/blog/images/streamlit-google-analytics/streamlit-google-analytics_headerimage.png"&gt;&lt;img alt="Jupyter Publishing Header Image" class="b-lazy" data-src="/blog/images/streamlit-google-analytics/streamlit-google-analytics_headerimage.png" src="https://elc.github.io/blog/images/streamlit-google-analytics/streamlit-google-analytics_headerimage-thumbnail.png" width="1444"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Streamlit is one of the most popular libraries for creating web apps using
Python, and they also provide 
&lt;a href="https://share.streamlit.io/" target="_blank"&gt;a service&lt;/a&gt; to freely host and
share your apps. One of the issues with this free sharing capability is that
one losses control over the app, for instance, it is no longer possible to
control how the precise HTML will look like or add custom
&lt;a href="https://en.wikipedia.org/wiki/Facebook_Platform#Open_Graph_protocol" target="_blank"&gt;Open Graph&lt;/a&gt;
or analytics. This post shows a simple and easy way to add all of this by using
Github Pages.&lt;/p&gt;


&lt;p&gt;This post is one part of a three posts series regarding Streamlit, the posts
can be read in any order and the three are built around the same demo app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Add Google Analytics (or any custom HTML) to Streamlit with Github Pages&lt;/strong&gt; (this post)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/posts/streamlit-multipage"&gt;Multipage, State-Persistent Apps with Streamlit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/posts/streamlit-lessons"&gt;Lessons learnt After Developing Finance Web Tools with Streamlit and Altair (No HTML/CSS/JS)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;&lt;a class="toclink" href="#tldr"&gt;TL;DR&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This post covers how to upload a Streamlit app to the Streamlit Sharing
platform and embed it as an iframe in a custom HTML hosted in Github Pages.
This is NOT suitable for sensitive data or commercial use.&lt;/p&gt;
&lt;p&gt;The technique used here &lt;em&gt;is a hack&lt;/em&gt;, meaning it is not the best practice, but
it will get the job done. In the end, a more &lt;em&gt;robust and professional&lt;/em&gt;
alternative will be mentioned for those interested.&lt;/p&gt;
&lt;p&gt;An &lt;a href="https://github.com/ELC/finance-tools" target="_blank"&gt;example Github Repo&lt;/a&gt;
is available for inspiration, there is also a 
&lt;a href="https://elc.github.io/finance-tools/" target="_blank"&gt;demo app&lt;/a&gt;
attached to check the final result.&lt;/p&gt;
&lt;h2 id="initial-clarification"&gt;&lt;a class="toclink" href="#initial-clarification"&gt;Initial Clarification&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This post assumes the Streamlit App is hosted via Streamlit Sharing since if
the app is being hosted on its own servers, there should not be a problem to add
tracking, Open Graph, or any custom HTML since one has full control over the
code and deployment. Instead, this post focuses on a purely free and managed
solution with no servers involved.&lt;/p&gt;
&lt;h2 id="streamlit-sharing"&gt;&lt;a class="toclink" href="#streamlit-sharing"&gt;Streamlit Sharing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Streamlit offers a free-forever Community plan for hosting and sharing an
unlimited number of public Streamlit apps, the &lt;a href="https://streamlit.io/cloud#plans" target="_blank"&gt;full plan comparison is available on their page&lt;/a&gt;.
To use that free service one has to create a free account and upload all the
code to a Github Repo (Gitlab, BitBucket, and Azure DevOps only in Paid plans
at the moment).&lt;/p&gt;
&lt;h3 id="deployment"&gt;&lt;a class="toclink" href="#deployment"&gt;Deployment&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To deploy a Streamlit app it is important not to have any uncommitted changes,
otherwise, streamlit will block the deployment. If all changes have been
committed (and pushed), first run the app locally, typically with:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;streamlit run python_script.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then go to the Hamburger Menu -&amp;gt; "Deploy this app"&lt;/p&gt;
&lt;p&gt;&lt;a href="/blog/images/streamlit-google-analytics/deploy-streamlit.png"&gt;&lt;img alt="Deploy to Streamlit" class="narrow b-lazy" data-src="/blog/images/streamlit-google-analytics/deploy-streamlit.png" src="https://elc.github.io/blog/images/streamlit-google-analytics/deploy-streamlit-thumbnail.png" width="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This will redirect to the Streamlit Sign in Page and after logging in, the
Deployment Options will be shown, here the repository, the branch, and the file
should be specified. It is also possible to add additional parameters (and even
secrets) in the "Advanced Settings", there is a &lt;a href="https://docs.streamlit.io/streamlit-cloud/get-started/deploy-an-app/connect-to-data-sources/secrets-management" target="_blank"&gt;tutorial to do this in the docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="/blog/images/streamlit-google-analytics/deployment-options.png"&gt;&lt;img alt="Deploy to Streamlit" class="narrow b-lazy" data-src="/blog/images/streamlit-google-analytics/deployment-options.png" src="https://elc.github.io/blog/images/streamlit-google-analytics/deployment-options-thumbnail.png" width="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once the app is deployed it should be available at a URL with this format:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;https://share.streamlit.io/GITHUB_USERNAME/REPOSITORY_NAME/MAIN_SCRIPT.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That URL is completely functional but it has the drawbacks mentioned in the
introduction, namely it is not possible to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add any kind of tracking/analytics&lt;/li&gt;
&lt;li&gt;Customize the Open Graph meta tags for social media sharing&lt;/li&gt;
&lt;li&gt;Add custom HTML&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is not possible however to alter the Javascript, the HTML, or the CSS of the
streamlit app itself because it is in a domain (&lt;code&gt;share.streamlit.io&lt;/code&gt;) to which
no access is granted. Nevertheless, analytics and meta tags are not "visible"
content and should therefore not disrupt the typical user experience of the
app. The main goal is to provide the final user with a seamless "Streamlit
Experience" while enhancing the features on the developer's end.&lt;/p&gt;
&lt;h2 id="github-pages"&gt;&lt;a class="toclink" href="#github-pages"&gt;Github Pages&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One advantage of Github repositories is that they come with a static webserver
directly built-in called "Github Pages". It is disabled by default, but can be
enabled by going to Settings -&amp;gt; Pages -&amp;gt; Enable. For simplicity, the master
branch will be used but other branches can be used if configured.&lt;/p&gt;
&lt;p&gt;&lt;a href="/blog/images/streamlit-google-analytics/github-pages.png"&gt;&lt;img alt="Deploy to Github Pages" class="narrow b-lazy" data-src="/blog/images/streamlit-google-analytics/github-pages.png" src="https://elc.github.io/blog/images/streamlit-google-analytics/github-pages-thumbnail.png" width="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once enabled, the root of the repository will be served at this URL:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;http://GITHUB_USERNAME.github.io/REPOSITORY_NAME
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That means that an &lt;code&gt;index.html&lt;/code&gt; can be added to the root of the repo and that
file will be the landing page of the URL.&lt;/p&gt;
&lt;p&gt;A basic HTML as the following can be used for testing:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;en&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;viewport&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;width=device-width, initial-scale=1.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;X-UA-Compatible&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ie=edge&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;My App&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hello World&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="embedding-streamlit"&gt;&lt;a class="toclink" href="#embedding-streamlit"&gt;Embedding Streamlit&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once both the Github Pages and the Streamlit Sharing are online, it is possible
to embed the latter in the former by using an &lt;code&gt;iframe&lt;/code&gt;. The &lt;code&gt;iframe`` by
default will show the app in smaller dimensions but with some minimal CSS it is
possible to extend the&lt;/code&gt;iframe` to provide the same look and feel as the
streamlit app.&lt;/p&gt;
&lt;p&gt;Moreover, it is also possible to add Google Analytics or another custom
HTML/CSS/JS into the page, always checking it does not affect the user
experience.&lt;/p&gt;
&lt;p&gt;The below example shows how to add the &lt;code&gt;iframe&lt;/code&gt; to the boilerplate shown in the
previous section.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;en&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;viewport&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;width=device-width, initial-scale=1.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;X-UA-Compatible&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ie=edge&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;My App&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="kt"&gt;vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="kt"&gt;vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://share.streamlit.io/GITHUB_USERNAME/REPOSITORY_NAME/MAIN_SCRIPT.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Your browser doesn&amp;#39;t support iframes
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To add Google Analytics, the JS snippet can be appended after the &lt;code&gt;iframe&lt;/code&gt;, do
remember to add the &lt;code&gt;google-site-verification&lt;/code&gt; as meta tag:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="na"&gt;lang&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;en&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;charset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;viewport&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;width=device-width, initial-scale=1.0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;X-UA-Compatible&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ie=edge&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="cm"&gt;&amp;lt;!-- Google Verification --&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;google-site-verification&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;GOOGLE_SITE_VERIFICATION_TOKEN&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;My App&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;#000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="kt"&gt;vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="kt"&gt;vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://share.streamlit.io/GITHUB_USERNAME/REPOSITORY_NAME/MAIN_SCRIPT.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        Your browser doesn&amp;#39;t support iframes
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="cm"&gt;&amp;lt;!-- Google Analytics --&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ga&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ga&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ga&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ga&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]).&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;ga&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;l&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;ga&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;create&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;UA_TRACKING_CODE&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;auto&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;ga&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;send&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;pageview&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;async&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;https://www.google-analytics.com/analytics.js&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With this last change and upon committing and pushing the Github Pages site
should show the Streamlit app seamlessly and it should also appear in the Real
Time tracking of Google Analytics.&lt;/p&gt;
&lt;h2 id="bonus-custom-domains"&gt;&lt;a class="toclink" href="#bonus-custom-domains"&gt;Bonus: Custom Domains&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As an additional advantage, Github Pages allows custom domain names, which, if
using streamlit is a paid-only feature. To learn more about this feature, check
the &lt;a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site" target="_blank"&gt;official docs&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="do-it-the-right-way"&gt;&lt;a class="toclink" href="#do-it-the-right-way"&gt;Do it the right way&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The steps described above can and should be considered merely a &lt;em&gt;hack&lt;/em&gt; since it
is not the intended way to use the Streamlit Sharing platform.&lt;/p&gt;
&lt;p&gt;There is indeed one other way to achieve the same, building a custom Streamlit
Component that achieves the same functionality. Streamlit Components are custom
Web Components that can extend the built-in Streamlit features, programming
those require React knowledge though and even if the result is &lt;em&gt;proper&lt;/em&gt; and of
higher quality it will be more time-consuming.&lt;/p&gt;
&lt;p&gt;If the &lt;em&gt;iframe-trick&lt;/em&gt; does not work for a given use case, using Streamlit
Components is a good next step.&lt;/p&gt;
&lt;p&gt;There is documentation about Streamlit Components in the &lt;a href="https://docs.streamlit.io/library/components/create" target="_blank"&gt;official Docs&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="other-alternatives"&gt;&lt;a class="toclink" href="#other-alternatives"&gt;Other Alternatives&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some alternatives to the shown method could be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run a Flask server and use Jinja2 to inject the custom HTML into the served
   streamlit&lt;/li&gt;
&lt;li&gt;Modify the default index.html the Streamlit library uses&lt;/li&gt;
&lt;li&gt;Host the HTML/CSS/JS snippet and embed that inside Streamlit using
   &lt;code&gt;st.components.v1.iframe&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All of these are either less &lt;em&gt;elegant&lt;/em&gt; or much more complex. The author
recommends either the &lt;em&gt;iframe-trick&lt;/em&gt; or &lt;em&gt;custom-components&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Streamlit is one of the most popular dashboarding platforms in the Python
Ecosystem and allows to create apps with ease, Streamlit Sharing provides a
free forever hosting platform for unlimited public apps. However, it is not
possible to add analytics or custom HTML out of the box. When embedded in a
static site like a plain &lt;code&gt;index.html&lt;/code&gt; and served via a free web server like
Github Pages one can add these features on top of it without issues.&lt;/p&gt;
&lt;p&gt;An &lt;a href="https://github.com/ELC/finance-tools" target="_blank"&gt;example Github Repo&lt;/a&gt; 
is available for inspiration, there is also a 
&lt;a href="https://elc.github.io/finance-tools/" target="_blank"&gt;demo app&lt;/a&gt;
attached to check the final result.&lt;/p&gt;
&lt;h2 id="check-the-series"&gt;&lt;a class="toclink" href="#check-the-series"&gt;Check the Series&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you liked this post, it is highly likely that you will also like the other
in this 3 part Streamlit Series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Add Google Analytics (or any custom HTML) to Streamlit with Github Pages&lt;/strong&gt; (this post)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/posts/streamlit-multipage"&gt;Multipage, State-Persistent Apps with Streamlit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/posts/streamlit-lessons"&gt;Lessons learnt After Developing Finance Web Tools with Streamlit and Altair (No HTML/CSS/JS)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Programming"></category><category term="Streamlit"></category><category term="Python"></category><category term="Github Pages"></category><category term="Google Analytics"></category></entry><entry><title>Lessons learnt After Developing Finance Web Tools with Streamlit and Altair (No HTML/CSS/JS)</title><link href="https://elc.github.io/posts/streamlit-lessons" rel="alternate"></link><published>2022-01-14T00:00:00-03:00</published><updated>2022-01-14T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2022-01-14:/posts/streamlit-lessons</id><summary type="html">&lt;p&gt;&lt;a href="/blog/images/streamlit-lessons/streamlit-lessons_headerimage.png"&gt;&lt;img alt="Jupyter Publishing Header Image" class="b-lazy" data-src="/blog/images/streamlit-lessons/streamlit-lessons_headerimage.png" src="https://elc.github.io/blog/images/streamlit-lessons/streamlit-lessons_headerimage-thumbnail.png" width="1444"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;There are a lot of resources available online about personal finances, stocks,
markets, cryptos, and many more economy-related topics. However the decisions
one has to make should be informed in order to be good enough. This post covers
the lessons learnt after developing similar tools using Streamlit and Altair.
No …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="/blog/images/streamlit-lessons/streamlit-lessons_headerimage.png"&gt;&lt;img alt="Jupyter Publishing Header Image" class="b-lazy" data-src="/blog/images/streamlit-lessons/streamlit-lessons_headerimage.png" src="https://elc.github.io/blog/images/streamlit-lessons/streamlit-lessons_headerimage-thumbnail.png" width="1444"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;There are a lot of resources available online about personal finances, stocks,
markets, cryptos, and many more economy-related topics. However the decisions
one has to make should be informed in order to be good enough. This post covers
the lessons learnt after developing similar tools using Streamlit and Altair.
No HTML/CSS/JS were needed. This post will make the reader aware of some pros
and cons of this libraries and also show an example app.&lt;/p&gt;


&lt;p&gt;This post is one part of a three posts series regarding Streamlit, the posts
can be read in any order and the three are built around the same demo app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lessons learnt After Developing Finance Web Tools with Streamlit and Altair (No HTML/CSS/JS)&lt;/strong&gt; (this post)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/posts/streamlit-google-analytics"&gt;Add Google Analytics (or any custom HTML) to Streamlit with Github Pages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/posts/streamlit-multipage"&gt;Multipage, State-Persistent Apps with Streamlit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="disclaimer"&gt;&lt;a class="toclink" href="#disclaimer"&gt;Disclaimer&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The author has no formal education in economics nor any related field, these
tools have been thought for personal use only and may contain bugs or
inaccuracies. They are provided for free "as is".&lt;/p&gt;
&lt;h2 id="tldr"&gt;&lt;a class="toclink" href="#tldr"&gt;TL;DR&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This post explains how this 
&lt;a href="https://elc.github.io/finance-tools/" target="_blank"&gt;web app&lt;/a&gt; 
was developed with a focus on  Streamlit, streamlit-multipage, NumPy, pandas
, and Altair. The full code is available on
&lt;a href="https://github.com/ELC/finance-tools" target="_blank"&gt;this Github Repo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The app covers topics like compound interest, flex term vs fixed terms,
inflation adjustment, fee recovery, and asset past profitability. If the reader
is already familiar with these topics, it is suggested to check the app and
come back in case of questions.&lt;/p&gt;
&lt;h2 id="warning"&gt;&lt;a class="toclink" href="#warning"&gt;Warning&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is NOT an economy/finance post, it is a technical post about the
&lt;strong&gt;development&lt;/strong&gt; of personal finance tools, do not expect full details about the
economic part, there are plenty of other resources online. This post will focus
on the Python implementation, in particular in the use of Streamlit,
Streamlit-MultiPage and Altair.&lt;/p&gt;
&lt;h2 id="personal-finance-tools"&gt;&lt;a class="toclink" href="#personal-finance-tools"&gt;Personal Finance Tools&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Finance is a subject that in many cases is not taught in the depth it should,
meaning there is a lot of confusion, misinformation and in many topics, scams.
That is why having open-source and free tools to help taking decisions is
critical nowadays.&lt;/p&gt;
&lt;p&gt;This is a showcase of some of what is possible with Python, thanks to libraries
like Streamlit that convert scripts into web apps and Altair that generate
transparent vector plots, it is now easy to develop tools that everyone can
use.&lt;/p&gt;
&lt;h3 id="the-state-of-the-art"&gt;&lt;a class="toclink" href="#the-state-of-the-art"&gt;The State of the Art&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the particular case of investing, there are already two pages that dominate
the market &lt;a href="https://www.investing.com/" target="_blank"&gt;Investing&lt;/a&gt; and
&lt;a href="https://www.tradingview.com/" target="_blank"&gt;TradingView&lt;/a&gt;. Both have free
and paid plans and this post does not focus on that type of apps, but rather
much simpler ones.&lt;/p&gt;
&lt;p&gt;For example, can someone confidently invest in stocks or crypto if they do not
understand how inflation or compound interest work? Sure it is technically
possible, but the decision is not informed. The apps developed help to fill
that gap and give the first contact with terms like inflation, interest and
Fixed/Flex Terms.&lt;/p&gt;
&lt;p&gt;At the moment on the internet there are plenty of online tools to achieve the
same, those, however, are typically calculators that only return a single value
and/or whose code is not available. In many cases, they "refer to the formula".
Those apps have a main focus on computing, not teaching, if someone does not
know how interests work, giving them the final interest at the end of the
period might help but it is not the whole story.&lt;/p&gt;
&lt;p&gt;That does not mean that the apps developed are the best online by any means
but, by providing the code and a more customizable UI, the user can experiment
more and "learn while doing" instead of staring at formulas that seem cryptic
at times.&lt;/p&gt;
&lt;h3 id="the-challenge"&gt;&lt;a class="toclink" href="#the-challenge"&gt;The Challenge&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Making something technically sound and user-friendly at the same time is a
challenging task. The more visual a tool is, the more likely it is for the
reader to understand how it is working and the underlying principle behind the
tool.&lt;/p&gt;
&lt;p&gt;Since the author has no formal education in economics or finance, it was also
important to provide an easy way for others to contribute to fix bugs and add
enhancements. That is why an open-source solution is a must in this case.&lt;/p&gt;
&lt;p&gt;To the best of the author's knowledge, there are no Python-based tools like the
developed, so the added-value lies not only in the tools themselves but also
because the project serves as a baseline for future related projects.&lt;/p&gt;
&lt;p&gt;It was also important to reduce the entry barrier as much as possible so that
only some programming skills are needed to extend the existing apps.&lt;/p&gt;
&lt;h3 id="the-result"&gt;&lt;a class="toclink" href="#the-result"&gt;The Result&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The result of this is having a web app that can be easily used by anyone
with or without programming/economics knowledge and it is as easy to maintain
and extend as possible. The app is 
&lt;a href="https://elc.github.io/finance-tools" target="_blank"&gt;already online&lt;/a&gt; 
and can be used.&lt;/p&gt;
&lt;p&gt;The next section will focus on the technology more in-depth.&lt;/p&gt;
&lt;h2 id="the-python-implementation"&gt;&lt;a class="toclink" href="#the-python-implementation"&gt;The Python Implementation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The project uses Python, a programming language with a mature ecosystem of
libraries like the Scipy Stack but at the same time it is an easy-to-learn
language which can be taught in very few time. &lt;/p&gt;
&lt;p&gt;That being said, to generate a fully working web app, web technologies should
be used. Fortunately, there are Python libraries that allow the developer to
bypass that step.&lt;/p&gt;
&lt;h3 id="stack"&gt;&lt;a class="toclink" href="#stack"&gt;Stack&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The different apps within the project use the same stack which is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.python.org/" target="_blank"&gt;Python&lt;/a&gt; as the base programming language&lt;/li&gt;
&lt;li&gt;&lt;a href="https://streamlit.io/" target="_blank"&gt;Streamlit&lt;/a&gt; to handle the "web part"&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ELC/streamlit-multipage" target="_blank"&gt;Streamlit-multipage&lt;/a&gt; to bundle different apps together&lt;/li&gt;
&lt;li&gt;[Altair]https://altair-viz.github.io/ for plots&lt;/li&gt;
&lt;li&gt;Scipy Stack (&lt;a href="https://numpy.org/" target="_blank"&gt;Numpy&lt;/a&gt;, &lt;a href="https://pandas.pydata.org/" target="_blank"&gt;Pandas&lt;/a&gt; and &lt;a href="https://scipy.org/" target="_blank"&gt;Scipy&lt;/a&gt;) to run simulations faster&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pypi.org/project/yfinance/" target="_blank"&gt;YFinance&lt;/a&gt; to download ticker information&lt;/li&gt;
&lt;li&gt;&lt;a href="https://joblib.readthedocs.io/" target="_blank"&gt;Joblib&lt;/a&gt; (optional) for the persistence of state, fallbacks to &lt;code&gt;pickle&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The choice of the dependencies and the pros and cons will be extended in the
upcoming sections. The main objective was to keep the project simple and avoid
lesser-known libraries when possible.&lt;/p&gt;
&lt;p&gt;All the code is 
&lt;a href="https://github.com/ELC/finance-tools" target="_blank"&gt;hosted on Github&lt;/a&gt; 
and can be starred, forked or clone right away.&lt;/p&gt;
&lt;h3 id="simulation-challenges"&gt;&lt;a class="toclink" href="#simulation-challenges"&gt;Simulation Challenges&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The defacto standard for numerical simulations is the Scipy Stack, there have
been some challenges though as some of the processes do not have a closed
formula one can translate to Python.&lt;/p&gt;
&lt;p&gt;In some cases like the Inflation Simulation a 
&lt;a href="https://github.com/ELC/finance-tools/blob/a4a138b55fb2fa1638a1ff763038736b9db14b41/pages/inflation.py#L74-L105" target="_blank"&gt;pure numpy solution&lt;/a&gt; 
could be achieved, but in others like the compound interest with recurring
deposits with a different frequency than the compounding frequency a 
&lt;a href="https://github.com/ELC/finance-tools/blob/a4a138b55fb2fa1638a1ff763038736b9db14b41/pages/common.py#L125-L178" target="_blank"&gt;for-loop&lt;/a&gt; 
approach was used.&lt;/p&gt;
&lt;p&gt;Nevertheless, even native for-loops being several orders of magnitude slower
than NumPy, that was not the bottleneck of the app. The bottleneck was the
plotting step, since the length of the data in these apps is usually under the
tens of thousands which is fast enough, even when using native for-loops.&lt;/p&gt;
&lt;p&gt;Having the app running locally would be enough for personal use however many
non-technical people would have been excluded when doing so. Therefore, having
the app available online is just as important as it working properly.&lt;/p&gt;
&lt;h3 id="deployment-process"&gt;&lt;a class="toclink" href="#deployment-process"&gt;Deployment Process&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To deploy Streamlit apps there are two alternatives:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hosted by &lt;a href="https://share.streamlit.io/" target="_blank"&gt;Streamlit Sharing&lt;/a&gt; (Community plan is free forever)&lt;/li&gt;
&lt;li&gt;Self-Hosted&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The self-hosted approach will involve either server or Docker configuration and
thus will not be covered in this post.&lt;/p&gt;
&lt;p&gt;The use of Streamlit Sharing and how to deploy a streamlit app there has been
already covered in detail in other of the posts in this Streamlit Series. That
post also covers how to achieve Google Analytics (or any custom HTML)
integration in the app, although that would be only relevant for the
tech-savvy.&lt;/p&gt;
&lt;h2 id="streamlit-review"&gt;&lt;a class="toclink" href="#streamlit-review"&gt;Streamlit Review&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Streamlit alone is a feature-rich, well-documented, and tested library,
however, it would have been impractical to have several small streamlit apps.
This is something also found in other online tools, they provide "Several
calculators" each in different pages hindering accessibility and visibility.&lt;/p&gt;
&lt;p&gt;However, streamlit does not support multi-page apps by default, which could be
achieve by using &lt;a href="https://github.com/ELC/streamlit-multipage" target="_blank"&gt;&lt;code&gt;streamlit-multipage&lt;/code&gt;&lt;/a&gt;
, a third-party library.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;DISCLAIMER&lt;/strong&gt;: The author is not the original developer of
&lt;code&gt;streamlit-multipage&lt;/code&gt; but has contributed significantly to that library.&lt;/p&gt;
&lt;p&gt;In one of the other posts in this Streamlit series, there is an extended
explanation on how to use this library and what is possible.&lt;/p&gt;
&lt;p&gt;The rest of this section will cover unresolved issues to consider when
developing this kind of apps.&lt;/p&gt;
&lt;h3 id="hot-reload-could-be-harmful"&gt;&lt;a class="toclink" href="#hot-reload-could-be-harmful"&gt;Hot reload could be harmful&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By default, each time there is a change in any of the Streamlit Visual
components, it triggers the execution of the whole app. This behavior might
deteriorate the user experience if there are many inputs and the process takes
more than a few seconds.&lt;/p&gt;
&lt;p&gt;Having a "Run Button" is possible without any plugins but the "magic update" of
streamlit is definitely a feature no one would want to lose.&lt;/p&gt;
&lt;h3 id="lack-of-skeleton-elements"&gt;&lt;a class="toclink" href="#lack-of-skeleton-elements"&gt;Lack of skeleton elements&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A related issue to the previously mentioned is that when streamlit is
"Loading" or "Processing" there is no visual hint for the user that this is the
case. No spinners, skeletons, or anything like that. This should not be a
problem for fast apps but in the case of taking several seconds, this might
result in a suboptimal user experience.&lt;/p&gt;
&lt;p&gt;There is no straightforward way to mitigate this besides programming the
loading/skeletons themselves as independent Streamlit Components.&lt;/p&gt;
&lt;h3 id="lack-of-basic-html-elements"&gt;&lt;a class="toclink" href="#lack-of-basic-html-elements"&gt;Lack of basic HTML Elements&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Streamlit combines Python and Web Technologies (in particular React) in a
clever way, abstracting every web-related from the Python side. That has its
costs though, thinking of custom yet basic HTML elements like a "Click me
Button" that redirects to a page might be non-trivial to do and might require
either custom HTML with styling or designing a React component just for that
which seems excesive.&lt;/p&gt;
&lt;p&gt;Streamlit is ideal for the use cases it was thought but deviating too much from
it might increase developing time significantly and make the learning curve
much steeper.&lt;/p&gt;
&lt;h3 id="persistence-might-be-complex"&gt;&lt;a class="toclink" href="#persistence-might-be-complex"&gt;Persistence might be complex&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Even though the &lt;code&gt;streamlit-multipage&lt;/code&gt; provides persistence mechanisms, they
were tested in Streamlit Sharing. This is because of how streamlit works under
the hood, it runs "the whole script" with every change, making any kind of
"initialization code" extremely hard to avoid repeating with each change.&lt;/p&gt;
&lt;p&gt;There is support for some basic native persistence through &lt;code&gt;st.session_state&lt;/code&gt;
but it has not been optimized for multipage apps nor it provides two-way
binding as one might be used to from Front-End frameworks.&lt;/p&gt;
&lt;h3 id="streamlit-conclusion"&gt;&lt;a class="toclink" href="#streamlit-conclusion"&gt;Streamlit Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Streamlit is not the only of its kind, there is Panel, Dash, Voila, and there
might be more in the future. That being said, Streamlit was the best tool for
the job in this case for many reasons, it does not really on other tools (dash
is heavily tiered towards plotly and voila works on Jupyter), and it has a
mature and responsive community (panel is lacking in this aspect.)&lt;/p&gt;
&lt;p&gt;Streamlit alone was initially not enough due to the lacking multipage support
but using &lt;code&gt;streamlit-multipage&lt;/code&gt; solved this without disrupting the streamlit
developer experience.&lt;/p&gt;
&lt;h2 id="altair-review"&gt;&lt;a class="toclink" href="#altair-review"&gt;Altair Review&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://altair-viz.github.io/" target="_blank"&gt;Altair&lt;/a&gt;
 is a plotting library that aims to provide a "declarative interface" rather
than a "descriptive interface", in practice, this allows for simpler code and
more code re-use.&lt;/p&gt;
&lt;p&gt;It is not the most popular tool by any means, that would be matplotlib but one
of the main disadvantages of the latter is that there is no support for
transparency. Transparency might be a not-so-important feature, but, since
Streamlit has a light and a dark theme, a transparent plot is necessary to
ensure a consistent visual design that is not compatible with Matplotlib.&lt;/p&gt;
&lt;p&gt;On the other side, matplotlib is much faster than Altair, this might change in
the future but at least when using Altair one has to limit the number of data
points to 5000. That being said, the interactiveness Altair provides makes it a
perfect fit for web apps.&lt;/p&gt;
&lt;p&gt;Learning Altair requires some time but if one is already familiar with
matplotlib the learning curve is a bit flatter. There are many good materials
already available to learn on 
&lt;a href="https://pyvideo.org/search.html?q=altair" target="_blank"&gt;PyVideo&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="verbosity-and-modularity"&gt;&lt;a class="toclink" href="#verbosity-and-modularity"&gt;Verbosity and Modularity&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Unless using the defaults, producing highly customized plots requires many
lines of code, regardless of the plotting library. The main difference with
Altair is that those "extra-custom-lines" could be re-use across plots.&lt;/p&gt;
&lt;p&gt;This is an example to add a text tooltip&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;selection&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;chart&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mark_text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;align&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;right&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dx&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dy&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;white&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontSize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform_filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;selection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This function returns an Altair object given a chart, a field, and a selection,
that means that one can add the same tooltip to many plots at the same time
while keeping the code centralized in a separate file.&lt;/p&gt;
&lt;p&gt;This is an underrated feature that allows to re-use code and becomes critical
when using multiple somewhat similar plots.&lt;/p&gt;
&lt;h3 id="altair-is-slow"&gt;&lt;a class="toclink" href="#altair-is-slow"&gt;Altair is slow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The main disadvantage of Altair is that everything that happens is handled over
to Vega-Lite, the library Altair is built on. This means that Altair is much
slower than other plotting libraries, this is especially true when compared
with matplotlib. &lt;/p&gt;
&lt;p&gt;Even so, having tooltips, panning and zooming are features that are worth the
wait and the final user will notice the difference because the quality of the
end result is evident.&lt;/p&gt;
&lt;h3 id="altair-conclusion"&gt;&lt;a class="toclink" href="#altair-conclusion"&gt;Altair Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are many options when deciding over a plotting library, the most popular
by far is Matplotlib, however, for web apps, it is lacking the features many
consider basic like zooming and panning. And having the possibility to re-use
code across plots is something that makes Altair a very good fit for any large
software project.&lt;/p&gt;
&lt;p&gt;There are drawbacks like the data point limit and the slowness, a balance
between the two should be found and it will depend on every app.&lt;/p&gt;
&lt;h2 id="overall-conclusion"&gt;&lt;a class="toclink" href="#overall-conclusion"&gt;Overall Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Developing Web Apps with Python has never been easier, Python has a strong
mathematical and computational stack that makes most computations fast and
efficient. It also has an ecosystem that makes it suitable for most use cases
and on top of that, it is considered one of the easiest programming languages
to learn.&lt;/p&gt;
&lt;p&gt;Thanks to libraries like Streamlit and Altair, one can now develop web apps and
make them available online so everyone can benefit from these amazing tools in
more tangible ways.&lt;/p&gt;
&lt;p&gt;There are some issues but the author believes this will be solved in the middle
term as the libraries evolve and improve themselves.&lt;/p&gt;
&lt;p&gt;The 
&lt;a href="https://elc.github.io/finance-tools/" target="_blank"&gt;Personal Finance Tools&lt;/a&gt; 
is online and ready to use, the code is 
&lt;a href="https://github.com/ELC/finance-tools" target="_blank"&gt;hosted in Github&lt;/a&gt; 
as well.&lt;/p&gt;
&lt;h2 id="check-the-series"&gt;&lt;a class="toclink" href="#check-the-series"&gt;Check the Series&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you liked this post, it is highly likely that you will also like the other
in this 3 part Streamlit Series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lessons learnt After Developing Finance Web Tools with Streamlit and Altair (No HTML/CSS/JS)&lt;/strong&gt; (this post)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/posts/streamlit-google-analytics"&gt;Add Google Analytics (or any custom HTML) to Streamlit with Github Pages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/posts/streamlit-multipage"&gt;Multipage, State-Persistent Apps with Streamlit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Programming"></category><category term="Streamlit"></category><category term="Python"></category><category term="Altair"></category></entry><entry><title>Multipage, State-Persistent Apps with Streamlit</title><link href="https://elc.github.io/posts/streamlit-multipage" rel="alternate"></link><published>2022-01-14T00:00:00-03:00</published><updated>2022-01-14T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2022-01-14:/posts/streamlit-multipage</id><summary type="html">&lt;p&gt;&lt;a href="/blog/images/streamlit-mutipage/streamlit-mutipage_headerimage.png"&gt;&lt;img alt="Jupyter Publishing Header Image" class="b-lazy" data-src="/blog/images/streamlit-mutipage/streamlit-mutipage_headerimage.png" src="https://elc.github.io/blog/images/streamlit-mutipage/streamlit-mutipage_headerimage-thumbnail.png" width="1444"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Converting a Python script to a web app has never been easier thanks to
libraries such as Streamlit. This library allows to create simple and
responsive web apps with minimal effort but there is one potential limitation:
No multipage support. In this post, a &lt;em&gt;potential&lt;/em&gt; solution to this problem is …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="/blog/images/streamlit-mutipage/streamlit-mutipage_headerimage.png"&gt;&lt;img alt="Jupyter Publishing Header Image" class="b-lazy" data-src="/blog/images/streamlit-mutipage/streamlit-mutipage_headerimage.png" src="https://elc.github.io/blog/images/streamlit-mutipage/streamlit-mutipage_headerimage-thumbnail.png" width="1444"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Converting a Python script to a web app has never been easier thanks to
libraries such as Streamlit. This library allows to create simple and
responsive web apps with minimal effort but there is one potential limitation:
No multipage support. In this post, a &lt;em&gt;potential&lt;/em&gt; solution to this problem is
presented with examples and demos. &lt;/p&gt;


&lt;p&gt;This post is one part of a three posts series regarding Streamlit, the posts
can be read in any order and the three are built around the same demo app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multipage, State-Persistent Apps with Streamlit&lt;/strong&gt; (this post)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/posts/streamlit-google-analytics"&gt;Add Google Analytics (or any custom HTML) to Streamlit with Github Pages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/posts/streamlit-lessons"&gt;Lessons learnt After Developing Finance Web Tools with Streamlit and Altair (No HTML/CSS/JS)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tldr"&gt;&lt;a class="toclink" href="#tldr"&gt;TL;DR&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is a pip installable plugin called &lt;code&gt;streamlit-multipage&lt;/code&gt;, this post is an
extension of the README of the &lt;a href="https://github.com/ELC/streamlit-multipage" target="_blank"&gt;Github Repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Try it yourself by doing&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install streamlit-multipage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;An &lt;a href="https://github.com/ELC/finance-tools" target="_blank"&gt;example Github Repo&lt;/a&gt; 
is available for inspiration, there is also a 
&lt;a href="https://elc.github.io/finance-tools/" target="_blank"&gt;demo app&lt;/a&gt;
attached to check the final result.&lt;/p&gt;
&lt;p&gt;For an alternative, more in-depth library, check
&lt;a href="https://github.com/TangleSpace/hydralit" target="_blank"&gt;Hydralit&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="why-multipage-apps"&gt;&lt;a class="toclink" href="#why-multipage-apps"&gt;Why Multipage Apps?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Streamlit is an awesome tool for converting Python scripts into Webapps but,
sometimes one wants to have many tiny scripts combined in a user-friendly way
and, even though it is possible to develop one streamlit app for each, the
process is tedious and the whole project loses maintainability.&lt;/p&gt;
&lt;p&gt;Multipage apps are apps that can host different apps in parallel with some
additional features like state persistence or customizable UI.&lt;/p&gt;
&lt;h2 id="streamlit-multipage"&gt;&lt;a class="toclink" href="#streamlit-multipage"&gt;Streamlit-multipage&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are several solutions to these problems and to the best of the author's
knowledge, these are the most popular ones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/TangleSpace/hydralit" target="_blank"&gt;Hydralit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/upraneelnihar/streamlit-multiapps" target="_blank"&gt;streamlit-multiapps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bvenkatesh-ai/streamlit_pages" target="_blank"&gt;streamlit-pages&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, for one reason or another, none of them fulfill the purpose of a
"simple multipage experience". &lt;/p&gt;
&lt;p&gt;&lt;code&gt;Hydralit&lt;/code&gt; is a bit overkill because it is a big
project deeply integrated with streamlit and one has to use &lt;code&gt;import hydralit as
hy&lt;/code&gt; instead of &lt;code&gt;import streamlit as st&lt;/code&gt; which breaks the typical idioms built
around streamlit.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Streamlit-Multiapps&lt;/code&gt; is not pip installable and has &lt;code&gt;NumPy&lt;/code&gt; and &lt;code&gt;pandas&lt;/code&gt; as
dependencies, which, even if used in most cases, are not required always and
are considered among the heaviest dependencies in the Python ecosystem.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Streamlit-pages&lt;/code&gt; is a 55 LoC script, which is too basic and provides no state
persistence options.&lt;/p&gt;
&lt;p&gt;There is a fourth option called &lt;a href="https://github.com/ELC/streamlit-multipage" target="_blank"&gt;&lt;code&gt;streamlit-multipage&lt;/code&gt;&lt;/a&gt; 
which is pip installable and it has state persistence while keeping streamlit
idioms. It is not as feature-rich as Hydralit but has a much more friendly
learning curve.&lt;/p&gt;
&lt;p&gt;In this post, the &lt;code&gt;streamlit-multipage&lt;/code&gt; will be used and covered in depth.&lt;/p&gt;
&lt;p&gt;To start working with this library one can simply install it via pip:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install streamlit-multipage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;DISCLAIMER&lt;/strong&gt;: The original development of &lt;code&gt;streamlit-multipage&lt;/code&gt; was done by
Yan Almeida, however, this blog's author contributed significantly to the
library. Most of this post content will be extracted from the repository README
with extended explanations.&lt;/p&gt;
&lt;h2 id="features"&gt;&lt;a class="toclink" href="#features"&gt;Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Streamlit-multipage has several appealing features that may be useful for most
users.&lt;/p&gt;
&lt;h2 id="simplicity"&gt;&lt;a class="toclink" href="#simplicity"&gt;Simplicity&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using &lt;code&gt;streamlit-multipage&lt;/code&gt; is as simple as writing a native streamlit like
this:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;streamlit&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;st&lt;/span&gt;

&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;My Amazing App&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Your Name: &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Hello &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And refactoring in a function like this&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;streamlit&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;st&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;streamlit_multipage&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;My Amazing App&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Your Name: &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Hello &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Hello World&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The function has to take one positional argument, ideally called &lt;code&gt;st&lt;/code&gt;, that is
the streamlit object. The function also needs to take arbitrary keyword
argument &lt;code&gt;**state&lt;/code&gt;, this is where the state of the app will be injected.&lt;/p&gt;
&lt;p&gt;As seen in the example, it is not necessary to use the &lt;code&gt;state&lt;/code&gt; variable at all
in the function.&lt;/p&gt;
&lt;p&gt;In the last part of the snippet, we see the &lt;code&gt;streamlit-multipage&lt;/code&gt; specific part
which consists of instantiating a &lt;code&gt;MultiPage&lt;/code&gt; object, passing the streamlit
object and then adding the app (or page) with the &lt;code&gt;add_app&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;This is ideal for short scripts but typically streamlit apps have many dozens
if not hundreds of lines of code, for that the function could be moved to a
different folder&lt;/p&gt;
&lt;p&gt;Since the &lt;code&gt;st&lt;/code&gt; object used will be passed as a parameter, it is not needed to
import streamlit anywhere else in the project besides where the &lt;code&gt;MultiPage&lt;/code&gt;
object was instantiated.&lt;/p&gt;
&lt;p&gt;Working in the functions &lt;em&gt;feels like native streamlit&lt;/em&gt; because it is,
the &lt;code&gt;st&lt;/code&gt; parameter is not a mocked object nor is it monkey patched, providing
the native streamlit experience.&lt;/p&gt;
&lt;h2 id="state-persistence"&gt;&lt;a class="toclink" href="#state-persistence"&gt;State Persistence&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another important feature is inter-page persistence, this is a type of
persistence that allows saving variables from one page to the other but it
also allows saving the state after restarting the app.&lt;/p&gt;
&lt;p&gt;Here is an example of this feature:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;streamlit&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;st&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;streamlit_multipage&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;input_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Body Mass Index&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;weight_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;weight&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;weight&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;number_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Your weight (Kg): &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;weight_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;height_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;height&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;height&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;number_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Your height (m): &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;height_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;weight&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;height&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Body Mass Index&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;weight&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;height&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Enter your data before computing. Go to the Input Page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;weight&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;height&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;BMI&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Input Page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;BMI Result&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;compute_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here the app "Input Page" can pass variables to the "BMI Result" page by
calling the &lt;code&gt;MultiPage.save&lt;/code&gt; method. By default, all the variables are saved in
a global namespace but different namespaces can be used as well (see next
example).&lt;/p&gt;
&lt;p&gt;To access the state on a page one has to use the &lt;code&gt;state&lt;/code&gt; variable, which is a
Python dictionary, simply checking if the necessary keys are present should be
enough. It is recommended to add warning messages if there are missing keys.&lt;/p&gt;
&lt;p&gt;If default values are desired for when the variables are not present the &lt;code&gt;get&lt;/code&gt;
method can be used as well.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;my_variable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Year&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Internally the state is persisted in a pickle file which uses
&lt;a href="https://joblib.readthedocs.io/en/latest/" target="_blank"&gt;&lt;code&gt;joblib&lt;/code&gt;&lt;/a&gt; 
if available, if it is not installed it gracefully fallsback to the native
&lt;a href="https://docs.python.org/3/library/pickle.html" target="_blank"&gt;pickle module&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt;: This feature has been tested locally but not with the Streamlit
Sharing Service (Deploy App Option).&lt;/p&gt;
&lt;h3 id="namespaces"&gt;&lt;a class="toclink" href="#namespaces"&gt;Namespaces&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;MultiPage.save&lt;/code&gt; method can take a second keyword argument &lt;code&gt;namespaces&lt;/code&gt;
which receives a list of all the namespaces the variables should be saved into.
That is, a page can save a variable in multiple namespaces.&lt;/p&gt;
&lt;p&gt;There is no efficiency or comprehension consideration in the implementation so
beware of storing heavy objects in multiple namespaces at once (especially
important for large NumPy arrays or tensors).&lt;/p&gt;
&lt;p&gt;When using namespaces it is a good practice to add a &lt;code&gt;namespace&lt;/code&gt; variable at
the very top of the function for easy reference.&lt;/p&gt;
&lt;p&gt;The example below illustrates this feature&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;streamlit&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;st&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;streamlit_multipage&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;input_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;input&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;variables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Tax Deduction&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;salary_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;salary&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;salary&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;number_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Your salary (USD): &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;salary_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;tax_percent_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tax_percent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tax_percent&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;tax_percent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;number_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Taxes (%): &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tax_percent_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;tax_percent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tax_percent&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;salary&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tax_percent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tax_percent&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;namespaces&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;total&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;namespaces&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;result&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;result&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;variables&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;namespace&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Your Salary After Taxes&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;total&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Enter your data before computing. Go to the Input Page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;total&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Total&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Input Page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Net Salary&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;compute_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When using custom namespaces, it is important to access &lt;code&gt;state[namespace]&lt;/code&gt;,
instead of the &lt;code&gt;state&lt;/code&gt; alone, because &lt;code&gt;state&lt;/code&gt; will contain all namespaces,
including the global one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt;: no variable in the global namespace should be named identically as
another namespace.&lt;/p&gt;
&lt;h3 id="automatic-namespaces"&gt;&lt;a class="toclink" href="#automatic-namespaces"&gt;Automatic Namespaces&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is also possible to avoid that altogether and use Automatic Namespaces,
&lt;code&gt;streamlit-multipage&lt;/code&gt; will filter the &lt;code&gt;state&lt;/code&gt; variable before passing it to a
function if it detects that there is a namespace with the same name of the app.
That is if the namespace is the same as the name used in the &lt;code&gt;add_app&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The namespace should be explicitly specified in the &lt;code&gt;MultiPage.save&lt;/code&gt;
method.&lt;/p&gt;
&lt;p&gt;This is an example of automatic namespaces&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;streamlit&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;st&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;streamlit_multipage&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;input_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Tax Deduction&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;salary_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;salary&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;salary&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;number_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Your salary (USD): &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;salary_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;tax_percent_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tax_percent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tax_percent&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;tax_percent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;number_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Taxes (%): &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tax_percent_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;tax_percent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tax_percent&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;salary&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tax_percent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tax_percent&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;namespaces&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Input Page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;total&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;namespaces&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Net Salary&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Your Salary After Taxes&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;total&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Enter your data before computing. Go to the Input Page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;total&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Total&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Input Page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Net Salary&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;compute_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="extensibility"&gt;&lt;a class="toclink" href="#extensibility"&gt;Extensibility&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When using &lt;code&gt;streamlit-multipage&lt;/code&gt; projects can grow easily within a directory
structure.&lt;/p&gt;
&lt;p&gt;Consider the following directory structure&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;.
└── root/
    ├── pages/
    │   ├── __init__.py
    │   ├── input_data.py
    │   └── result.py
    └── main.py/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here the &lt;code&gt;main.py&lt;/code&gt; is the entry point, it imports both &lt;code&gt;streamlit&lt;/code&gt; and
&lt;code&gt;streamlit-multipage&lt;/code&gt;, it instantiates the &lt;code&gt;MultiPage&lt;/code&gt; object and loads the
pages and adds them to the object.&lt;/p&gt;
&lt;p&gt;Each app or page can be separated into its file and common code could be
abstracted as well.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;__init__.py&lt;/code&gt; facilitates the import hierarchy by giving a single entry
point to the &lt;code&gt;pages&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;These could be the content of the files:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;input_data.py&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;streamlit_multipage&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;input_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Tax Deduction&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;salary_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;salary&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;salary&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;number_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Your salary (USD): &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;salary_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;tax_percent_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;tax_percent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tax_percent&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="n"&gt;tax_percent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;number_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Taxes (%): &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tax_percent_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;tax_percent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tax_percent&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;salary&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;salary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tax_percent&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tax_percent&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;namespaces&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Input Page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;total&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;namespaces&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Net Salary&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;results.py&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Your Salary After Taxes&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;total&amp;quot;&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Enter your data before computing. Go to the Input Page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;total&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Total&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;__init__.py&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.input_data&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;input_page&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;.result&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;compute_page&lt;/span&gt;

&lt;span class="n"&gt;pages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;Input Page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;input_page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;Net Salary&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;compute_page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;main.py&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;pages&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;streamlit&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;st&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;streamlit_multipage&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app_function&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pages&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;app_function&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Structuring the application this way makes all the files much shorter and with
a single responsibility. This could have been done with just &lt;code&gt;streamlit&lt;/code&gt; but
with minor modifications &lt;/p&gt;
&lt;h2 id="customization"&gt;&lt;a class="toclink" href="#customization"&gt;Customization&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is also possible to add customizations to each app to enhance the user
experience such as adding a header, a footer, additional sidebar elements,
hiding the hamburger menu and customizing the default text (e.g. for
localization)&lt;/p&gt;
&lt;p&gt;This code shows how these customizations can be used:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;streamlit&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;st&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;streamlit_multipage&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;save&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;input_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;See Example on Multipage&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;See Example on Multipage&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Developed by [ELC](https://elc.github.io)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;This app is free to use&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sidebar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Donate (Dummy)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MultiPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start_button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Go to the main page&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;navbar_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Other Pages:&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;next_page_button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Next Chapter&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;previous_page_button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Previous Chapter&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reset_button&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Delete Cache&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;navbar_style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;SelectBox&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;footer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;footer&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;navbar_extra&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sidebar&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hide_menu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hide_navigation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Input Page&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_app&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;BMI Result&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;compute_page&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="non-functional-features"&gt;&lt;a class="toclink" href="#non-functional-features"&gt;Non-Functional Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In addition to the previous functional features, there are some non-functional
ones that could be interesting for some.&lt;/p&gt;
&lt;h3 id="single-file-project"&gt;&lt;a class="toclink" href="#single-file-project"&gt;Single-File Project&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Streamlit-multipage&lt;/code&gt; is a single file project, meaning that instead of pip
install it and add a dependency to track, the whole project can be simply add
as a library in any other project standalone and it should work out of the box.&lt;/p&gt;
&lt;h2 id="quality-of-code"&gt;&lt;a class="toclink" href="#quality-of-code"&gt;Quality of Code&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The code has been formatted with &lt;a href="https://github.com/psf/black" target="_blank"&gt;Black&lt;/a&gt; 
and Type Hints were added whenever possible to improve integration with
editors and IDEs.&lt;/p&gt;
&lt;h2 id="limitations"&gt;&lt;a class="toclink" href="#limitations"&gt;Limitations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The library itself has its limitations, namely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The state is saved in a dictionary and then in a pickled file, there is no
  usage of &lt;code&gt;st.session_state&lt;/code&gt; which would imply a better user experience, this
  has been tried but due to &lt;code&gt;streamlit&lt;/code&gt; lacking two-way binding in the
  &lt;code&gt;session_state&lt;/code&gt;, this is not possible at the moment.&lt;/li&gt;
&lt;li&gt;There are no tests, according to &lt;a href="https://discuss.streamlit.io/t/how-can-you-py-test-your-code/400" target="_blank"&gt;this discussion&lt;/a&gt;,
  it is not straightforward to test streamlit apps nor libraries built around
  it, mainly because this involves testing not only Python but also Front-End
  code. This has not been done so far, contributions are much welcome though.&lt;/li&gt;
&lt;li&gt;Integration with Streamlit Sharing has not been tested thoroughly, the basic
  multi-page app works but no state management has been tested on the managed
  service. All the features shown in this post have been manually tested on a
  locally running streamlit app.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Streamlit is one of the most popular tools for dashboarding and easily
converting Python Scripts into Web Apps. &lt;code&gt;Streamlit-Multipage&lt;/code&gt; is a lightweight
app that can be pip installable (or drop in a standalone script) that allows
for seamless integration of multi-page apps while keeping state and idioms.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;streamlit-multipage&lt;/code&gt; has no tests and has not been thoroughly tested on
the Streamlit Sharing but for self-hosted apps should be working without
issues.&lt;/p&gt;
&lt;p&gt;An &lt;a href="https://github.com/ELC/finance-tools" target="_blank"&gt;example Github Repo&lt;/a&gt; 
is available for inspiration, there is also a 
&lt;a href="https://elc.github.io/finance-tools/" target="_blank"&gt;demo app&lt;/a&gt;
attached to check the final result using the &lt;code&gt;streamlit-multipage&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="check-the-series"&gt;&lt;a class="toclink" href="#check-the-series"&gt;Check the Series&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you liked this post, it is highly likely that you will also like the other
in this 3 part Streamlit Series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multipage, State-Persistent Apps with Streamlit&lt;/strong&gt; (this post)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/posts/streamlit-google-analytics"&gt;Add Google Analytics (or any custom HTML) to Streamlit with Github Pages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/posts/streamlit-lessons"&gt;Lessons learnt After Developing Finance Web Tools with Streamlit and Altair (No HTML/CSS/JS)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Programming"></category><category term="Streamlit"></category><category term="Python"></category><category term="Github"></category></entry><entry><title>Secure Live Collaboration in Jupyter Lab</title><link href="https://elc.github.io/posts/jupyter-collaborative" rel="alternate"></link><published>2021-09-04T00:00:00-03:00</published><updated>2021-09-04T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2021-09-04:/posts/jupyter-collaborative</id><summary type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/jupyter-collaborative-headerimage.png"&gt;&lt;img alt="Jupyter Publishing Header Image" class="b-lazy" data-src="/blog/images/jupyter-collaborative/jupyter-collaborative-headerimage.png" src="https://elc.github.io/blog/images/jupyter-collaborative/jupyter-collaborative-headerimage-thumbnail.png" width="1444"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;The single most requested feature for Jupyter Notebooks/Lab was live
collaboration &lt;em&gt;á la Google Docs&lt;/em&gt;. Today, this is possible but should be done
with caution, since it gives access to the whole internet to run any (including
malicious) code on our local PC. This is a quick guide to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/jupyter-collaborative-headerimage.png"&gt;&lt;img alt="Jupyter Publishing Header Image" class="b-lazy" data-src="/blog/images/jupyter-collaborative/jupyter-collaborative-headerimage.png" src="https://elc.github.io/blog/images/jupyter-collaborative/jupyter-collaborative-headerimage-thumbnail.png" width="1444"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;The single most requested feature for Jupyter Notebooks/Lab was live
collaboration &lt;em&gt;á la Google Docs&lt;/em&gt;. Today, this is possible but should be done
with caution, since it gives access to the whole internet to run any (including
malicious) code on our local PC. This is a quick guide to prevent this by
implementing several layers of security.&lt;/p&gt;


&lt;h2 id="collaborative-notebooks"&gt;&lt;a class="toclink" href="#collaborative-notebooks"&gt;Collaborative Notebooks&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are many ways to work collaboratively, however not all are suitable for
every scenario. In the case of Jupyter Notebooks, there are three main types of
collaboration, the last of which has been introduced recently.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Asincronous Multiuser&lt;/strong&gt;: each party makes changes and then changes are
  merged. This is git-like collaboration and is possible with Jupyter Notebooks
  out of the box.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Non-Concurrent Multiuser&lt;/strong&gt;: Several users make changes at the same time but
  not in the same files. This is currently possible when using Jupyter-Hub (or
  MyBinder) servers. There might be synchronization issues if modifying the
  same file.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concurrent Multiuser&lt;/strong&gt;: Several users make changes at the same time in any
  document (even the same one) and the changes are merged without overlapping.
  This is the Google Docs style and is the new feature of Jupyter. Hereafter
  this is the type of collaboration that will be referred to as &lt;strong&gt;live
  collaboration&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-should-we-work-collaboratively"&gt;&lt;a class="toclink" href="#why-should-we-work-collaboratively"&gt;Why should we work collaboratively?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Working collaboratively has definite some advantages, one way to show them is
by some example use cases that would not be possible without this feature:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A teacher can invite their students to actively collaborate on a notebook and
  write comments and questions in a centralized way.&lt;/li&gt;
&lt;li&gt;A small team can leverage a server (or powerful computer) to run the
  notebooks instead of each having to run the kernels on their local PCs.&lt;/li&gt;
&lt;li&gt;Two team members can work in different parts of the same problem, like
  hyperparameter tuning and data visualization concurrently.&lt;/li&gt;
&lt;li&gt;A presenter can invite a small audience to try some Jupyter app (e.g. built
  with widgets) and have them use it with zero-install.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, this is probably not the best solution for all possible scenarios
but for small teams, mentoring / teaching and showing proof of concepts, it
might be worthwhile.&lt;/p&gt;
&lt;p&gt;The results are illustrated in the following video&lt;/p&gt;
&lt;video width="1920" controls autoplay muted&gt;
  &lt;source src="https://elc.github.io/blog/images/jupyter-collaborative/Jupyter_Collaborative_demo.mp4" type="video/mp4"&gt;
Your browser does not support the HTML5 video.
&lt;/video&gt;

&lt;h2 id="risks-involved"&gt;&lt;a class="toclink" href="#risks-involved"&gt;Risks involved&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before enabling live collaboration, it is important to understand the risks it
implies. Therefore three different use cases will be illustrated:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Host a Jupyter Notebook on the local PC and work together with someone in
   the same local network (LAN or VPN)&lt;/li&gt;
&lt;li&gt;Host a Jupyter Notebook on the local PC and work together with someone
   outside of the local network (any PC with internet access)&lt;/li&gt;
&lt;li&gt;Host a Jupyter Notebook on a remote PC and work together with someone
   outside the local network&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first is mostly secure (as long as the local network can be trusted).
However, when giving access to the whole internet (the second option), some
security measures should be taken. The third case is too vaguely described to
be explained in detail since the steps might change for servers behind a
reverse proxy, servers in the cloud, or servers on-premises, furthermore, some
servers require specific firewall changes. For on-home, on-premise servers
steps should be similar to what is described for the second case.&lt;/p&gt;
&lt;h2 id="quick-solution"&gt;&lt;a class="toclink" href="#quick-solution"&gt;Quick Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This article covers some of the technical details and implications of each of
the steps. It is recommended &lt;strong&gt;to read the full article&lt;/strong&gt; but for those who
already had and/or want a quick solution, refer to the
&lt;a href="#summary-quick-steps-to-follow"&gt;4-command-summary&lt;/a&gt; at the end.&lt;/p&gt;
&lt;h2 id="important-disclaimer"&gt;&lt;a class="toclink" href="#important-disclaimer"&gt;&lt;span style="color:Crimson"&gt;&lt;strong&gt;Important Disclaimer&lt;/strong&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This article assumes you have full control of the PC you are going to use, I
highly recommend &lt;strong&gt;against&lt;/strong&gt; using these guide on any company-owned hardware to
avoid introducing security risks and/or going against the company's policies.&lt;/p&gt;
&lt;p&gt;Moreover, I am &lt;strong&gt;not&lt;/strong&gt; a security expert so I strongly recommend the reader to
make their research and validate everything here written because fine
details might be overlooked.&lt;/p&gt;
&lt;p&gt;Finally, take into consideration that this tutorial is &lt;strong&gt;OPENING A
BACKDOOR&lt;/strong&gt; for your PC so, one can never have too many security measures. If
this makes you feel uneasy, do all your experiments inside a sandbox (like a
container or a virtual machine).&lt;/p&gt;
&lt;p&gt;To further illustrate this, Ribaka Nazmara 
&lt;a href="https://www.quora.com/What-is-the-most-dangerous-Python-line-of-code/answer/Ribaka-Nazmara" target="_blank"&gt;showed in Quora&lt;/a&gt;
some dangerous yet simple code a malicious user might run:&lt;/p&gt;
&lt;p&gt;Fill up disk:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt; 

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Delete all files:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt; 

&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;rm -rf /&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Crash the system:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt; 
&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;%0|%0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;From Python, one can even run processes in the background with the &lt;code&gt;subprocess&lt;/code&gt;
module. These examples should illustrate why not using adequate security
measures might result in disastrous outcomes.&lt;/p&gt;
&lt;h2 id="requirements"&gt;&lt;a class="toclink" href="#requirements"&gt;Requirements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This tutorial requires Jupyter Lab 3.1.0 or newer and NGrok (for the second use
case). &lt;/p&gt;
&lt;p&gt;If ngrok is not installed, all the steps are explained in 
&lt;a href="https://calmcode.io/ngrok/the-problem.html" target="_blank"&gt;this 5 minute tutorial&lt;/a&gt; 
by CalmCode.&lt;/p&gt;
&lt;p&gt;In the case of Jupyter Lab, the version required was &lt;a href="https://pypi.org/project/jupyterlab/3.1.0/"&gt;released on the 27th of
July 2021&lt;/a&gt; so if Jupyterlab was not
installed recently, an update will be needed.&lt;/p&gt;
&lt;p&gt;To check your Jupyter Lab version simply run:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;jupyter lab --version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="jupyter-lab-update-instructions"&gt;&lt;a class="toclink" href="#jupyter-lab-update-instructions"&gt;Jupyter Lab Update Instructions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If using Anaconda, run:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;conda update anaconda
conda update jupyterlab
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For traditional pip installations, run:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install jupyterlab&amp;gt;=3.1.0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="use-case-1-collaborative-work-inside-lan-or-vpn"&gt;&lt;a class="toclink" href="#use-case-1-collaborative-work-inside-lan-or-vpn"&gt;Use Case 1: Collaborative work inside LAN or VPN&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/network_diagram_1.png"&gt;&lt;img alt="Ngrok HTTP" class="narrow b-lazy" data-src="/blog/images/jupyter-collaborative/network_diagram_1.png" src="https://elc.github.io/blog/images/jupyter-collaborative/network_diagram_1-thumbnail.png" width="826"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once Jupyterlab 3.1.0 or newer is installed, it is possible to enable the
collaborative feature by running:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;jupyter lab --collaborative
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will create a normal session available at http://localhost:8888. However,
this URL is only accessible inside your local network. To access from another
device (PC or Mobile) one should replace the "localhost" with the &lt;em&gt;private IP
address&lt;/em&gt;, also known as &lt;em&gt;internal IP&lt;/em&gt;. The IP address is a network address and
is not attached to specific hardware (as the MAC address), which means that
each time the PC is turned on, it might have a different private IP.&lt;/p&gt;
&lt;p&gt;To know your private IP simply run this command in a terminal&lt;/p&gt;
&lt;p&gt;On Linux/Mac:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ifconfig -a
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On Windows:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ipconfig
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Private IPs are the ones following these formats:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Class A: from 10.0.0.0 to 10.255.255.255&lt;/li&gt;
&lt;li&gt;Class B: from 172.16.0.0 to 172.31.255.255&lt;/li&gt;
&lt;li&gt;Class C: from 192.168.0.0 to 192.168.255.255&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The "Default Gateway" IP is the one for your router or networking device
whereas the other one (Ethernet, IPv4, or similar) is the one of the PC.&lt;/p&gt;
&lt;p&gt;For example, if the PC's IP address is 192.168.1.35 any person connected &lt;strong&gt;to
the same network&lt;/strong&gt; could access the Jupyter session by navigating to the URL
http://192.168.1.35:8888 in the browser. &lt;strong&gt;Note&lt;/strong&gt;: This required that the port
8888 is open in the firewall of the PC running Jupyter.&lt;/p&gt;
&lt;p&gt;By default, Jupyter uses Token Authentication which is transparently applied
for the local PC, meaning that incoming connections from other PCs will be
rejected or they will be asked to provide a token.&lt;/p&gt;
&lt;p&gt;Tokens are difficult to share and remember as they are long strings of
seemingly random text, that is why they will be replaced with a user-defined
password.&lt;/p&gt;
&lt;h3 id="first-layer-of-security-jupyter-password"&gt;&lt;a class="toclink" href="#first-layer-of-security-jupyter-password"&gt;First Layer of Security: Jupyter Password&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/network_diagram_2.png"&gt;&lt;img alt="Ngrok HTTP" class="narrow b-lazy" data-src="/blog/images/jupyter-collaborative/network_diagram_2.png" src="https://elc.github.io/blog/images/jupyter-collaborative/network_diagram_2-thumbnail.png" width="826"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The Jupyter CLI provides a straightforward way to set a global password by
running:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;jupyter lab --generate-config
jupyter lab password
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first command generates a default config file, if already run before, it
can be omitted. The second one will prompt the user to write a password and
then confirm it. &lt;strong&gt;Note&lt;/strong&gt;: when writing the password, no characters (not even
"*") will be shown, this is done so that the number of characters of the
password is kept secret, this is common practice in Linux Systems but may be
new for some users.&lt;/p&gt;
&lt;p&gt;Continuing the previous example, when a user from another PC enters the
http://localhost:8888, it can access by writing the pre-defined password.&lt;/p&gt;
&lt;p&gt;If configured correctly, the next time Jupyter is run, it will prompt for the
password:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/jupyter_password.png"&gt;&lt;img alt="Ngrok HTTP" class="narrow b-lazy" data-src="/blog/images/jupyter-collaborative/jupyter_password.png" src="https://elc.github.io/blog/images/jupyter-collaborative/jupyter_password-thumbnail.png" width="790"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Technical Details&lt;/strong&gt;: The password is stored as a hashed in the configuration
file, so it is not stored as plain-text anywhere in the system and is a global
setting for all Jupyter Lab sessions (Jupyter Notebook sessions are not
affected). &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important Note&lt;/strong&gt;: Always refer to the 
&lt;a href="https://jupyter-notebook.readthedocs.io/en/stable/public_server.html" target="_blank"&gt;Official Docs&lt;/a&gt;
in case some of the information presented here changes.&lt;/p&gt;
&lt;h3 id="second-layer-of-security-local-tls-encryption"&gt;&lt;a class="toclink" href="#second-layer-of-security-local-tls-encryption"&gt;Second Layer of Security: Local TLS Encryption&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/network_diagram_3.png"&gt;&lt;img alt="Ngrok HTTP" class="narrow b-lazy" data-src="/blog/images/jupyter-collaborative/network_diagram_3.png" src="https://elc.github.io/blog/images/jupyter-collaborative/network_diagram_3-thumbnail.png" width="826"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Even having configured a password, the connection is not encrypted, which means
that, inside the local network, the password travels as plain text through the
network and thus is susceptible to man-in-the-middle attacks.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/jupyter_insecure.png"&gt;&lt;img alt="Ngrok HTTP" class="narrow b-lazy" data-src="/blog/images/jupyter-collaborative/jupyter_insecure.png" src="https://elc.github.io/blog/images/jupyter-collaborative/jupyter_insecure-thumbnail.png" width="488"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you trust your VPN or local network, this step is &lt;strong&gt;optional&lt;/strong&gt;.
Nevertheless, this is &lt;strong&gt;mandatory&lt;/strong&gt; when using public networks (cafés,
airports, etc.).&lt;/p&gt;
&lt;p&gt;To prevent this from happening, a protocol with encryption (like HTTPS) should
be used. HTTPS is the most common approach, it uses TLS encryption so all the
data sent between two nodes is encrypted, which of course includes the password
that would have otherwise traveled as plain text.&lt;/p&gt;
&lt;p&gt;Explaining how certificates (the key component of TLS encryption) work is
beyond the scope of this article. Nonetheless, one can set up quite easily a
self-signed certificate, the browser will show a warning saying the connection
&lt;em&gt;might be insecure&lt;/em&gt; but that is simply because the certificate does not come
from a &lt;strong&gt;Certificate Authority&lt;/strong&gt;, a company that is trusted to emit valid and
trustworthy certificates. Instead, the certificate is emitted by the user in
the local PC is not suitable for any production environment but is more enough
for this use case.&lt;/p&gt;
&lt;p&gt;To generate this certificate the simplest way is to use OpenSSL which is
already installed if using Anaconda. In case Anaconda is not installed, OpenSSL
should be installed independently. Using Anaconda is however the easiest way
for Windows users.&lt;/p&gt;
&lt;p&gt;Once OpenSSL is installed, navigate to the folder where Jupyter will be started
and run:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout mykey.key -out mycert.pem
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: if the error: "Can't open {some_path}ssl/openssl.cnf for reading, No
such file or directory" is thrown, see the next section to configure it using
Anaconda.&lt;/p&gt;
&lt;p&gt;Once run, it will generate two files, the mykey.key, and the mycert.pem, &lt;strong&gt;none
of which should be added to source control&lt;/strong&gt;. These two files will enable the
Jupyter server to use HTTPS for its connections, to do so, run the following
command:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;jupyter lab --collaborative --certfile=mycert.pem --keyfile mykey.key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This setup should suffice but, the user should be instructed to use
https://localhost:8888 (with HTTPS) explicitly because there might not be an
automatic redirection to HTTPS if using HTTP. The browser might show a warning
as described earlier but this should be ignored and continue anyways.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/jupyter_self_signed.png"&gt;&lt;img alt="Ngrok HTTP" class="b-lazy" data-src="/blog/images/jupyter-collaborative/jupyter_self_signed.png" src="https://elc.github.io/blog/images/jupyter-collaborative/jupyter_self_signed-thumbnail.png" width="1508"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To remove the browser warning one should add the local certificate to the
truststore, that, however, is beyond the scope of this article.&lt;/p&gt;
&lt;p&gt;With the previous configuration the connection between the PC running Jupyter
and the other PC is encrypted, even inside the Local Network / VPN.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: so far, the whole connection is done through the local network and
should not be visible from outside, but in public networks, this might be
different. The good practice is to never trust a public network, with the
password and this connection encryption a &lt;em&gt;decent&lt;/em&gt; level of security is
achieved for local connections / VPN &lt;strong&gt;only&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In the following sections, this will be expanded to cover users from other
networks (i.e. internet). Hence additional security measures should be taken.&lt;/p&gt;
&lt;h3 id="config-file-missing"&gt;&lt;a class="toclink" href="#config-file-missing"&gt;Config file Missing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The configuration file for OpenSSL is not configured by default therefore one
has to run:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;set OPENSSL_CONF={AnacondaPath}/pkgs/openssl-1.1.1k-{some_hash}/Library/ssl/openssl.cnf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="use-case-2-collaborative-work-outside-the-local-network"&gt;&lt;a class="toclink" href="#use-case-2-collaborative-work-outside-the-local-network"&gt;Use Case 2: Collaborative work outside the local network&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is not the most common to have multiple users in the same local network, for
those cases, one should establish a connection with someone through the
internet. By doing so, the local PC is open to &lt;strong&gt;anyone&lt;/strong&gt; with enough knowledge
to hack and get themselves in.&lt;/p&gt;
&lt;p&gt;There is no way to guarantee 100% that no one unintended will be granted
access, there are some measures one could take against though.&lt;/p&gt;
&lt;p&gt;The first layer of security described above is a must, having at least
password-protection is the bare minimum when connecting through the internet.&lt;/p&gt;
&lt;p&gt;Moreover, in this section, several additional layers of security will be
described and at the end, a quick summary will be given to help the reader get
started in as little time as possible.&lt;/p&gt;
&lt;p&gt;To set up an open connection to our computer, ngrok is a good solution. After
installing it, and adding it to the Path, and providing the auth token, one can
simply open connections in a single command:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ngrok http 8888
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command is enough to open the connection, and since our Jupyter
environment is password-protected, there is no immediate threat. And this
provides an additional layer of security out of the box: &lt;strong&gt;obscurity&lt;/strong&gt;, which
will be explained further in the next section.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/ngrok_http.png"&gt;&lt;img alt="Ngrok HTTP" class="b-lazy" data-src="/blog/images/jupyter-collaborative/ngrok_http.png" src="https://elc.github.io/blog/images/jupyter-collaborative/ngrok_http-thumbnail.png" width="1306"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;However, if one navigates to the URL shown, a 403 Forbidden message will be
displayed:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/ngrok_forbidden.png"&gt;&lt;img alt="Ngrok HTTP" class="narrow b-lazy" data-src="/blog/images/jupyter-collaborative/ngrok_forbidden.png" src="https://elc.github.io/blog/images/jupyter-collaborative/ngrok_forbidden-thumbnail.png" width="413"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is a security measure from Jupyter, it forbids all non-local connections:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/jupyter_blocking.png"&gt;&lt;img alt="Ngrok HTTP" class="b-lazy" data-src="/blog/images/jupyter-collaborative/jupyter_blocking.png" src="https://elc.github.io/blog/images/jupyter-collaborative/jupyter_blocking-thumbnail.png" width="1745"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To allow non-local connections the &lt;code&gt;ServerApp.allow_remote_access&lt;/code&gt; should be
enabled. This can be done from the Jupyter Config file created with the
&lt;code&gt;--generate-config&lt;/code&gt; command. Simply append this line to the end of the file:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServerApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allow_remote_access&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now after restarting the Jupyter instance, the URL provided by ngrok should be
accessible:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/ngrok_success.png"&gt;&lt;img alt="Ngrok HTTP" class="narrow b-lazy" data-src="/blog/images/jupyter-collaborative/ngrok_success.png" src="https://elc.github.io/blog/images/jupyter-collaborative/ngrok_success-thumbnail.png" width="645"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="possible-error-failed-to-complete-tunnel-connection"&gt;&lt;a class="toclink" href="#possible-error-failed-to-complete-tunnel-connection"&gt;Possible Error: Failed to complete tunnel connection&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If a message like the following is shown:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/failed_tunnel.png"&gt;&lt;img alt="Ngrok HTTP" class="narrow b-lazy" data-src="/blog/images/jupyter-collaborative/failed_tunnel.png" src="https://elc.github.io/blog/images/jupyter-collaborative/failed_tunnel-thumbnail.png" width="790"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This means that there is no service running at port 8888. This means that
Jupyter is either not running or is being served on another port.&lt;/p&gt;
&lt;h3 id="local-certificate"&gt;&lt;a class="toclink" href="#local-certificate"&gt;Local Certificate&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By default, when using a port as the destination, ngrok will point to the HTTP
as in http://localhost. However, when using the second layer of security and
implementing local TLS the above command should be rewritten to explicitly
target https://localhost as follows:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ngrok http https://localhost:8888
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/ngrok_http_to_https.png"&gt;&lt;img alt="Ngrok HTTP" class="b-lazy" data-src="/blog/images/jupyter-collaborative/ngrok_http_to_https.png" src="https://elc.github.io/blog/images/jupyter-collaborative/ngrok_http_to_https-thumbnail.png" width="1373"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is an optional extra step, only needed when the local network is not
trusted (e.g. public networks). This is &lt;strong&gt;mandatory&lt;/strong&gt; when used in combination
with the second layer of security described earlier.&lt;/p&gt;
&lt;h3 id="third-layer-of-security-obscurity"&gt;&lt;a class="toclink" href="#third-layer-of-security-obscurity"&gt;Third Layer of Security: Obscurity&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/network_diagram_4.png"&gt;&lt;img alt="Ngrok HTTP" class="b-lazy" data-src="/blog/images/jupyter-collaborative/network_diagram_4.png" src="https://elc.github.io/blog/images/jupyter-collaborative/network_diagram_4-thumbnail.png" width="1026"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ngrok will generate a pseudo-random sequence of characters for the URL of the
connection. One might think this is a disadvantage or a limited feature of the
free plan (since the paid plan support custom subdomains) but, having a
hard-to-guess sequence at the beginning is similar to a password, since both
parties should know it beforehand to establish the connection.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;https://7b42-201-212-74-100.ngrok.io
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Another advantage of this approach is that if a given URL is compromised, one
can simply re-run the ngrok command and get a new one with practically no
downtime.&lt;/p&gt;
&lt;p&gt;The clear disadvantage is that this method will impede any long-lasting
communication mechanism with the involved users (e.g. email), and one should
fall back on instant messaging methods (e.g. chats, calls, etc.). Nonetheless,
if the computer running the Jupyter will be kept on for long periods (like a
server), this drawback can be neglected.&lt;/p&gt;
&lt;p&gt;That being said, obscurity on its own is not a robust security measure, it will
not stand against deliberate malicious attacks but it constitutes a bare minimum
layer of confidentiality.&lt;/p&gt;
&lt;p&gt;When inspecting the console output, one can see that ngrok actually does two
forwarding connections, one for the HTTP and the other for the HTTPS. For
reasons already explained, if an encrypted connection is needed (as it is here
because we will be sending credentials), the HTTPS should be enforced by
rejecting any incoming non-HTTPS connections. Ngrok facilitates this with a
simple flag as explained in the next section.&lt;/p&gt;
&lt;h3 id="fourth-layer-of-security-public-tls-encryption"&gt;&lt;a class="toclink" href="#fourth-layer-of-security-public-tls-encryption"&gt;Fourth Layer of Security: Public TLS Encryption&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/network_diagram_5.png"&gt;&lt;img alt="Ngrok HTTP" class="b-lazy" data-src="/blog/images/jupyter-collaborative/network_diagram_5.png" src="https://elc.github.io/blog/images/jupyter-collaborative/network_diagram_5-thumbnail.png" width="1026"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The second layer of security introduced self-signed certificates for the
connections inside the local network (LAN or VPN), ngrok supports TLS
encryption with certificates coming from a Certificate Authority (CA) as part
of the free plan. However, the default behavior is to allow both HTTP (without
certificates) and HTTPS (with certificates).&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/ngrok_with_without.png"&gt;&lt;img alt="Ngrok HTTP" class="b-lazy" data-src="/blog/images/jupyter-collaborative/ngrok_with_without.png" src="https://elc.github.io/blog/images/jupyter-collaborative/ngrok_with_without-thumbnail.png" width="1296"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To enforce the use of HTTPS simply run:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ngrok http -bind-tls=true 8888
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The console output now shows only one forwarding connection from HTTPS and all
attempts to connect to HTTP will be forwarded to HTTPS.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/ngrok_https_only.png"&gt;&lt;img alt="Ngrok HTTP" class="b-lazy" data-src="/blog/images/jupyter-collaborative/ngrok_https_only.png" src="https://elc.github.io/blog/images/jupyter-collaborative/ngrok_https_only-thumbnail.png" width="1310"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The main difference with the second layer of security is that ngrok uses a
certificate coming from a CA and hence the browser displays no warning
whatsoever, resulting in a smoother experience for the final user.&lt;/p&gt;
&lt;p&gt;One limitation of the approach described so far is that the Jupyter password
is set globally for the local PC, and in case it is compromised, it may be
inconvenient to re-share the new password to all users. To mitigate this, it is
possible to generate a per-session username and password. This procedure is
explained in the next section.&lt;/p&gt;
&lt;h3 id="fifth-layer-of-security-http-password"&gt;&lt;a class="toclink" href="#fifth-layer-of-security-http-password"&gt;Fifth Layer of Security: HTTP Password&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/network_diagram_6.png"&gt;&lt;img alt="Ngrok HTTP" class="b-lazy" data-src="/blog/images/jupyter-collaborative/network_diagram_6.png" src="https://elc.github.io/blog/images/jupyter-collaborative/network_diagram_6-thumbnail.png" width="1026"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The HTTP protocol implements a basic authentication system via a
username-password combination. These two fields travel as plain text unless
the connection is encrypted (e.g. by using HTTPS), since the ngrok connection
is already configured to only accept HTTPS, the username and password will
travel through the internet encrypted.&lt;/p&gt;
&lt;p&gt;The free plan of ngrok also includes support for this authentication method and
can be enabled by adding &lt;code&gt;username:password&lt;/code&gt; to the command:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ngrok http -bind-tls=true -auth=&amp;quot;any_username:sesion_password&amp;quot; 8888
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These credentials will be asked upon connecting to the ngrok URL&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/ngrok_basic_auth.png"&gt;&lt;img alt="Ngrok HTTP" class="narrow b-lazy" data-src="/blog/images/jupyter-collaborative/ngrok_basic_auth.png" src="https://elc.github.io/blog/images/jupyter-collaborative/ngrok_basic_auth-thumbnail.png" width="603"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;After introducing the correct credentials, the password for the Jupyter server
will be asked.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/ngrok_basic_auth_success.png"&gt;&lt;img alt="Ngrok HTTP" class="narrow b-lazy" data-src="/blog/images/jupyter-collaborative/ngrok_basic_auth_success.png" src="https://elc.github.io/blog/images/jupyter-collaborative/ngrok_basic_auth_success-thumbnail.png" width="528"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This has an unintended advantage and that is that all attempts to log in are
against Ngrok servers and not our Jupyter Server. Providing a somewhat basic
defense against DDoS attacks.&lt;/p&gt;
&lt;p&gt;With everything done up to this point, there are several layers of defenses.
One of the things not done yet was filtering. There are several types of
filters one can implement, being the most common IP and MAC filtering. In the
next section, IP filtering is explained.&lt;/p&gt;
&lt;h3 id="sixth-layer-of-security-ip-whitelist"&gt;&lt;a class="toclink" href="#sixth-layer-of-security-ip-whitelist"&gt;Sixth Layer of Security: IP Whitelist&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/jupyter-collaborative/network_diagram_7.png"&gt;&lt;img alt="Ngrok HTTP" class="b-lazy" data-src="/blog/images/jupyter-collaborative/network_diagram_7.png" src="https://elc.github.io/blog/images/jupyter-collaborative/network_diagram_7-thumbnail.png" width="1026"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ngrok provides an IP Whitelist feature, this is feature is only supported in
the paid plans. Having the possibility to only allow certain IPs is useful as
long as the users connecting have static IP addresses and they indeed know
them.&lt;/p&gt;
&lt;p&gt;The most common scenario is that a user does not know their IP address and
even if they do it is hard to track when those are dynamically assigned (as it
is with several ISPs).&lt;/p&gt;
&lt;p&gt;In an enterprise setting, this is less convoluted since most PCs are connected
through a VPN, and the VPN usually has a range of public IP addresses, thus
whitelisting those makes the service only available for those in the company
network.&lt;/p&gt;
&lt;p&gt;For more information regarding this, check the 
&lt;a href="https://ngrok.com/docs#whitelist-manage" target="_blank"&gt;official docs&lt;/a&gt;
of ngrok.&lt;/p&gt;
&lt;p&gt;This article has described some of the possible security measures one can take
to securely connect to a Jupyter instance, the following sections will
summarize the content showed in quick steps and finally, some pitfalls will be
mentioned to avoid potential security risks.&lt;/p&gt;
&lt;h2 id="summary-quick-steps-to-follow"&gt;&lt;a class="toclink" href="#summary-quick-steps-to-follow"&gt;Summary: Quick steps to follow&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="1-update-jupyter-lab"&gt;&lt;a class="toclink" href="#1-update-jupyter-lab"&gt;1. &lt;strong&gt;Update Jupyter Lab&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Update Jupyter Lab to a 3.1.0 o newer with:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;conda update anaconda
conda update jupyterlab
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="2-set-a-password"&gt;&lt;a class="toclink" href="#2-set-a-password"&gt;2. &lt;strong&gt;Set a Password&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;jupyter lab --generate-config
jupyter lab password
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="3-enable-non-local-connections"&gt;&lt;a class="toclink" href="#3-enable-non-local-connections"&gt;3. &lt;strong&gt;Enable non-local connections&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Append this line to the config file generated in the previous step:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServerApp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allow_remote_access&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="4-run-ngrok"&gt;&lt;a class="toclink" href="#4-run-ngrok"&gt;4. &lt;strong&gt;Run Ngrok&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Run Ngrok with HTTPS only and providing username and password credentials&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ngrok http -bind-tls=true -auth=&amp;quot;any_username:sesion_password&amp;quot; 8888
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To avoid manually writing this file every time, a config file can be used to
automate the process. Steps to follow are shown in this 
&lt;a href="https://calmcode.io/ngrok/configuration.html" target="_blank"&gt;video&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="5-share-with-users"&gt;&lt;a class="toclink" href="#5-share-with-users"&gt;5. &lt;strong&gt;Share with users&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Share the Jupyter password via a long-lasting communication mechanism (e.g.
email), then share the ngrok URL and the associated username and password via
some instant messaging (e.g. chat). For extra security use two different
methods for the URL and the username-password, like sharing the
username-password via a screen share and the URL via chat.&lt;/p&gt;
&lt;h3 id="6-work-together-with-live-collaboration"&gt;&lt;a class="toclink" href="#6-work-together-with-live-collaboration"&gt;6. &lt;strong&gt;Work Together with Live Collaboration&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now everything is set up to work collaboratively.&lt;/p&gt;
&lt;h3 id="7-publish-your-work"&gt;&lt;a class="toclink" href="#7-publish-your-work"&gt;7. &lt;strong&gt;Publish your work&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Whenever the project is public, it is worth sharing. When working with Jupyter
Notebooks there are several ways to do it. In 
&lt;a href="https://elc.github.io/posts/jupyter-publishing/" target="_blank"&gt;this survey&lt;/a&gt; 
some of the most popular options are explained.&lt;/p&gt;
&lt;h2 id="common-pitfalls-and-questions"&gt;&lt;a class="toclink" href="#common-pitfalls-and-questions"&gt;Common Pitfalls and Questions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Everything has been configured and now the environment has at least some basic
security measures. However, there are some common pitfalls to be aware of.&lt;/p&gt;
&lt;h3 id="explicitly-ignore-your-sensitive-files-in-source-control"&gt;&lt;a class="toclink" href="#explicitly-ignore-your-sensitive-files-in-source-control"&gt;Explicitly Ignore your sensitive files in source control&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When using source control (e.g. git), the &lt;code&gt;.pem&lt;/code&gt; and &lt;code&gt;.key&lt;/code&gt; should be ignored
as well as any pre-configuration files from ngrok and jupyter. Otherwise, the
credentials and certificates are compromised.&lt;/p&gt;
&lt;h3 id="choose-different-and-hard-to-crack-passwords"&gt;&lt;a class="toclink" href="#choose-different-and-hard-to-crack-passwords"&gt;Choose different and hard-to-crack Passwords&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is useless to use two passwords if those are not different from each other,
good passwords are easy to read, easy to remember, and hard to guess. Against
what might be popular on the internet, using phrases as passwords is quite
useful and effective.&lt;/p&gt;
&lt;p&gt;Since the Jupyter password will be applied to all sessions, it should be
strong, preferably more than 16 characters long, whereas the Ngrok basic auth
could be something longer than 10 characters. &lt;/p&gt;
&lt;p&gt;To check password security by using some &lt;a href="https://howsecureismypassword.net/" target="_blank"&gt;service online&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="unreasonable-trust-in-ngrok"&gt;&lt;a class="toclink" href="#unreasonable-trust-in-ngrok"&gt;Unreasonable Trust in ngrok&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this article, ngrok is assumed to be a trusted organization, however, there
are no particular reasons one should trust ngrok. This post was not sponsored
by them or any other company and using the approaches here described put an
amount of trust in a free service some might find uncomfortable.&lt;/p&gt;
&lt;p&gt;For the typical user of Jupyter Notebooks, it is unlikely that the weakest
point in the security pipeline is ngrok but, for the conservative,
security-driven users, this is something to carefully evaluate.&lt;/p&gt;
&lt;p&gt;Ngrok will have access to the basic auth and for them, the Jupyter password
will be visible so they will have backdoor access to your PC. However, to the
best of the author's knowledge, there are no issues reported as security
breaches from ngrok.&lt;/p&gt;
&lt;p&gt;Another important point is that everything is built on the free plan from
ngrok, should they change the scope of the features of the free plan, some part
or all the procedure here describes might be obsolete. This is another
potential risk, because there is no guarantee the free service will stay free
as with the same features long-term.&lt;/p&gt;
&lt;h3 id="not-suitable-for-unlimited-connections"&gt;&lt;a class="toclink" href="#not-suitable-for-unlimited-connections"&gt;Not suitable for unlimited connections&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Even being generous, the free plan has its limitations and the collaboration
features might be limited to a handful of users (probably not more than a
couple of dozens). The free plan will likely fail to support hundreds of users
as in live conferences, a MOOC, or similar events.&lt;/p&gt;
&lt;p&gt;This approach is suitable for personal/hobbyist use or small teams (&amp;lt; 10
people). So far there are no benchmarks available as to how many users
concurrently can be working using collaborative Jupyter Lab with ngrok.&lt;/p&gt;
&lt;h3 id="remember-no-system-is-100-secure"&gt;&lt;a class="toclink" href="#remember-no-system-is-100-secure"&gt;Remember no system is 100% secure&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is an approach, it only showcases one possible way of doing things and
there might be better and more secure ones. However, I consider this is a good
tradeoff between technical complexity and practicality.&lt;/p&gt;
&lt;p&gt;As mentioned at the beginning, I am not a security expert and it is up to you
to double-check, all the information given and assess whether it is useful for
your particular scenario.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The new collaborative feature of Jupyter Lab is out of beta and ready to be
used. Some security measures should be taken beforehand to avoid any potential
breaches or risks. After understanding the underlying concepts, the new
Jupyter Lab can be run and set up in just 2 commands.&lt;/p&gt;
&lt;h2 id="contribute"&gt;&lt;a class="toclink" href="#contribute"&gt;Contribute¶&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This content is free and promotes both free and open source software, as well
as monetary and intellectual accessibility. If you want to support it, please
check out the privacy-first ad at the top of this page. Helping with fixing
typos, suggesting edits, or leaving feedback in the comments is also valuable.
If you like this content, please share it with others who might find it useful.&lt;/p&gt;
&lt;p&gt;If you want to contribute financially, invite me a
&lt;a href="https://ko-fi.com/elcweb"&gt;Ko-Fi&lt;/a&gt; or send me donation via
&lt;a href="https://www.paypal.com/donate/?hosted_button_id=948W4CFPMY2R2"&gt;PayPal&lt;/a&gt;. If you
are in Argentina, you can invite me a &lt;a href="https://cafecito.app/elc"&gt;Cafecito&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="resources"&gt;&lt;a class="toclink" href="#resources"&gt;Resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://jupyter-notebook.readthedocs.io/en/stable/public_server.html" target="_blank"&gt;Jupyter Official Documentation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Transport_Layer_Security" target="_blank"&gt;TLS Encryption&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://ngrok.com/docs" target="_blank"&gt;Ngrok Official Docs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.jupyter.org/how-we-made-jupyter-notebooks-collaborative-with-yjs-b8dff6a9d8af" target="_blank"&gt;Jupyter Collaborative Feature&lt;/a&gt;&lt;/p&gt;</content><category term="Programming"></category><category term="Jupyter"></category><category term="security"></category><category term="Ngrok"></category><category term="collaboration"></category></entry><entry><title>Jupyter Publishing Guide: From Embedded to Book</title><link href="https://elc.github.io/posts/jupyter-publishing" rel="alternate"></link><published>2021-08-16T00:00:00-03:00</published><updated>2021-08-16T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2021-08-16:/posts/jupyter-publishing</id><summary type="html">&lt;p&gt;&lt;a href="/blog/images/jupyter-publishing/jupyter-publishing-headerimage.png"&gt;&lt;img alt="Jupyter Publishing Header Image" class="b-lazy" data-src="/blog/images/jupyter-publishing/jupyter-publishing-headerimage.png" src="https://elc.github.io/blog/images/jupyter-publishing/jupyter-publishing-headerimage-thumbnail.png" width="1444"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Jupyter Notebooks are the lingua franca for Data Science. There is hardly any
data scientist that has never used this IDE. However, in contrast to its
popularity and usefulness, the process of sharing a Jupyter Notebook is not
straightforward. This article presents a brief survey of the different
publishing solutions …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="/blog/images/jupyter-publishing/jupyter-publishing-headerimage.png"&gt;&lt;img alt="Jupyter Publishing Header Image" class="b-lazy" data-src="/blog/images/jupyter-publishing/jupyter-publishing-headerimage.png" src="https://elc.github.io/blog/images/jupyter-publishing/jupyter-publishing-headerimage-thumbnail.png" width="1444"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Jupyter Notebooks are the lingua franca for Data Science. There is hardly any
data scientist that has never used this IDE. However, in contrast to its
popularity and usefulness, the process of sharing a Jupyter Notebook is not
straightforward. This article presents a brief survey of the different
publishing solutions available for personal and/or commercial projects.&lt;/p&gt;


&lt;h2 id="jupyter-notebooks"&gt;&lt;a class="toclink" href="#jupyter-notebooks"&gt;Jupyter Notebooks&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Jupyter notebooks are used everywhere in the Data Science ecosystem. They are
present without exceptions, from Coursera Courses to projects by FAANG. It is
normal then to ask, once a work has been done, how one can conveniently publish
the results. The answer may not be satisfactory: "There is no well-known,
commonly used, standard way to publish Jupyter Notebooks". Instead, there are
co-existing solutions that target different personas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Will the results be presented to a non-technical audience?&lt;/li&gt;
&lt;li&gt;Will those results aim at reproducibility?&lt;/li&gt;
&lt;li&gt;Is the focus solely on the code? Those questions require different solutions
  as there is no one-size-fits-all.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this post, a showcase of solutions for the different use cases will be
presented to the reader so that one can find the right tool for the job.&lt;/p&gt;
&lt;p&gt;A general classification for the solutions could be as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Share notebooks among developers&lt;/li&gt;
&lt;li&gt;Share notebooks online&lt;ul&gt;
&lt;li&gt;Read-Only&lt;/li&gt;
&lt;li&gt;Read and Execute&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Print notebooks&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All solutions here assume the only hardware and software available are the ones
used to work with the Jupyter Notebooks, i.e. no server or backend. Moreover,
every solution presented is either open-source or free to use, both for
personal and commercial use cases.&lt;/p&gt;
&lt;p&gt;This post will follow a cookbook approach, so feel free to jump ahead to the
section of interest, they are all self-contained. Each solution will contain
advantages, disadvantages, and a "when to use" section.&lt;/p&gt;
&lt;h2 id="index"&gt;&lt;a class="toclink" href="#index"&gt;Index&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#optional-a-bit-of-context-the-ipynb-format"&gt;Context on .ipynb&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#using-built-ins-export-solutions"&gt;Built-in Solutions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#read-only-solutions"&gt;Read Only Solutions&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#github-publishing"&gt;Gihub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#nbviewer-publishing"&gt;NBViewer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#static-site-generator-integration"&gt;Static Site Generator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#jupyter-book-static"&gt;Static Jupyter Book&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#executable-solutions"&gt;Executable Solutions&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#jupyter-lite"&gt;JupyterLite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#embedded-solution"&gt;Embedded&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#google-colaboratory"&gt;Google Colab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#my-binder"&gt;MyBinder&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#jupyter-book-executable"&gt;Executable Jupyter Book&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#printable-solutions"&gt;Printable Solutions&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#built-in-export-latex"&gt;LaTeX Export&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#jupyter-book-for-printing"&gt;LaTeX/PDF Jupyter Book&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#honorable-mentions"&gt;Honorable Mentions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#choose-the-best-tool"&gt;What should I use?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#additional-resources"&gt;Additional Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="optional-a-bit-of-context-the-ipynb-format"&gt;&lt;a class="toclink" href="#optional-a-bit-of-context-the-ipynb-format"&gt;(Optional) A bit of Context: The .ipynb format&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="/blog/images/jupyter-publishing/ipynb-format.png"&gt;&lt;img alt="IPYNB format" class="narrow b-lazy" data-src="/blog/images/jupyter-publishing/ipynb-format.png" src="https://elc.github.io/blog/images/jupyter-publishing/ipynb-format-thumbnail.png" width="500"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The format for a Jupyter notebook is JSON, but the extension used is &lt;code&gt;ipynb&lt;/code&gt;.
The reason behind using a different extension is twofold:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Not every JSON is a valid .ipynb.&lt;/li&gt;
&lt;li&gt;The file, although plain text, is not meant to be modified manually.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;When using Jupyter, the most common ways include &lt;code&gt;Jupyter Notebook&lt;/code&gt; and
&lt;code&gt;Jupyter Lab&lt;/code&gt;, and it is through these tools that modifications are written
into the underlying .json file. That ensures the file is always valid.
Modifying the .json manually could make the whole notebook unreadable and such
errors and difficult both to find and fix.&lt;/p&gt;
&lt;p&gt;The official documentation for this format is available as the
&lt;a href="https://nbformat.readthedocs.io/en/latest/" target="_blank"&gt;&lt;code&gt;nbformat&lt;/code&gt;&lt;/a&gt;
Python Package.&lt;/p&gt;
&lt;h3 id="problems-with-the-format"&gt;&lt;a class="toclink" href="#problems-with-the-format"&gt;Problems with the format&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This JSON-based format is also the main cause of trouble when working in teams,
such as edit collaboratively and version control. That is why tools such as
&lt;a href="https://blog.jupyter.org/how-we-made-jupyter-notebooks-collaborative-with-yjs-b8dff6a9d8af" target="_blank"&gt;&lt;code&gt;Yjs&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://nbdime.readthedocs.io/en/latest/" target="_blank"&gt;&lt;code&gt;nbdime&lt;/code&gt;&lt;/a&gt; were developed to solve those issues, respectively.&lt;/p&gt;
&lt;h3 id="developer-exchange"&gt;&lt;a class="toclink" href="#developer-exchange"&gt;Developer Exchange&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All that said, among developers, .json files are just ordinary everyday files,
and exchanging them is nothing new. On the other hand, even if those files are
&lt;em&gt;easy to send&lt;/em&gt;, one does require a whole setup (Python + Jupyter) to properly
visualize the content of such files. That is why the first and most simple way
to share and publish a notebook is through the built-in Export solutions.&lt;/p&gt;
&lt;h2 id="using-built-ins-export-solutions"&gt;&lt;a class="toclink" href="#using-built-ins-export-solutions"&gt;Using Built-Ins: Export Solutions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="/blog/images/jupyter-publishing/html-export.png"&gt;&lt;img alt="IPYNB format" class="narrow b-lazy" data-src="/blog/images/jupyter-publishing/html-export.png" src="https://elc.github.io/blog/images/jupyter-publishing/html-export-thumbnail.png" width="703"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Jupyter, in particular JupyterLab, introduces &lt;a href="https://jupyterlab.readthedocs.io/en/stable/user/export.html" target="_blank"&gt;several formats&lt;/a&gt;
for exporting the notebook. However, in this section one will be highlighted: 
&lt;strong&gt;HTML&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="advantages"&gt;&lt;a class="toclink" href="#advantages"&gt;Advantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;It can be sent in most commonly used media such as email, instant messaging
  apps like WhatsApp or Telegram, corporate team communication tools like MS
  Teams, Slack, and Google Chat.&lt;/li&gt;
&lt;li&gt;It is self-contained, i.e. it is a single-file export.&lt;/li&gt;
&lt;li&gt;It shows the notebook in the most similar way possible to what is shown when
  using Jupyter Notebook/Lab.&lt;/li&gt;
&lt;li&gt;It does not require any additional tools to display, not even on mobile
  devices.&lt;/li&gt;
&lt;li&gt;It is compatible with Analytics solutions like Google Analytics (should be
  added manually).&lt;/li&gt;
&lt;li&gt;It is copy/paste friendly for code.&lt;/li&gt;
&lt;li&gt;It correctly shows all formulae written in LaTeX.&lt;/li&gt;
&lt;li&gt;It is plain text and thus version control friendly.&lt;/li&gt;
&lt;li&gt;It displays all the outputs from the executed notebook, including plots and
  images.&lt;/li&gt;
&lt;li&gt;It can be easily hosted on any web server without a special back-end.&lt;/li&gt;
&lt;li&gt;It does not require any additional tool or set up for the export, only two
  clicks with the default Jupyter Installation.&lt;/li&gt;
&lt;li&gt;It can display interactive visualization tools like Altair if the output is
  plain HTML/JS (provided that the library supports it).&lt;/li&gt;
&lt;li&gt;There are no dependencies on third parties.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="disadvantages"&gt;&lt;a class="toclink" href="#disadvantages"&gt;Disadvantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;It is not editable. - Technically it is, but not in the same way a Jupyter
  notebook is.&lt;/li&gt;
&lt;li&gt;It cannot be executed, i.e. it is a static file.&lt;/li&gt;
&lt;li&gt;It has no support for a common revision mechanism (notes, comments,
  highlighting, etc.).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use"&gt;&lt;a class="toclink" href="#when-to-use"&gt;When to use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This solution is the best when the other person, for some reason, will not run
the notebook. For example, when sending sample code to a fellow developer, for
documentation examples, and also for simple web hosting.&lt;/p&gt;
&lt;p&gt;Some examples of this approach can be found in the PyMC3 official
documentation, where &lt;a href="https://docs.pymc.io/nb_examples/index.html" target="_blank"&gt;all their examples&lt;/a&gt; 
are HTML exports of Jupyter Notebooks.&lt;/p&gt;
&lt;h3 id="why-not-other-export-formats"&gt;&lt;a class="toclink" href="#why-not-other-export-formats"&gt;Why not other export formats?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Some may argue that &lt;strong&gt;PDF&lt;/strong&gt; is also a good choice. However, due to pagination,
generally the content and the output is split in unpredictable ways and thus
making it harder for the reader to understand, as Jupyter Notebooks were not
conceived to be read in separate pages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Asciidoc&lt;/strong&gt;, &lt;strong&gt;ReStructuredText&lt;/strong&gt;, &lt;strong&gt;Markdown&lt;/strong&gt; and &lt;strong&gt;LaTeX&lt;/strong&gt; require special
readers and assume that the other person also knows the format. Moreover, it is
not easy to display on mobile devices without any additional software.&lt;/p&gt;
&lt;p&gt;Executable Scripts (&lt;strong&gt;.py&lt;/strong&gt;) are plain text and hence they sacrifice all the
effort put in formatting and styling the markdown cells. And, if that was not
the case, why bothering having a Jupyter Notebook at all to begin?&lt;/p&gt;
&lt;p&gt;Finally, &lt;strong&gt;Reveal.js&lt;/strong&gt; is meant for presentations and it is a certainly useful
option for that matter, but it often shows a subset of the whole notebook and
it is meant for the author itself and not for third parties.&lt;/p&gt;
&lt;h2 id="read-only-solutions"&gt;&lt;a class="toclink" href="#read-only-solutions"&gt;Read-Only Solutions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Even though the last section covered HTML, which is also read-only, this
section will focus on non-built-it approaches. Moreover, all of the solutions
presented require some configuration or additional steps, the results might be
worthwhile depending on the particular scenario.&lt;/p&gt;
&lt;h2 id="github-publishing"&gt;&lt;a class="toclink" href="#github-publishing"&gt;Github Publishing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="/blog/images/jupyter-publishing/github-jupyter.png"&gt;&lt;img alt="Gitub HTML" class="b-lazy" data-src="/blog/images/jupyter-publishing/github-jupyter.png" src="https://elc.github.io/blog/images/jupyter-publishing/github-jupyter-thumbnail.png" width="1831"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Github is the most widespread solution for hosted git version control
repositories, this is also the case for the whole &lt;a href="https://github.com/jupyter" target="_blank"&gt;Project Jupyter&lt;/a&gt;, 
whose repositories are
hosted in this platform. With time, they &lt;a href="https://docs.github.com/en/github/managing-files-in-a-repository/working-with-non-code-files/working-with-jupyter-notebook-files-on-github" target="_blank"&gt;included a feature&lt;/a&gt; 
that shows the Jupyter Notebook as HTML without requiring the user to do such 
conversion.&lt;/p&gt;
&lt;p&gt;The view will be the same as the one with the HTML export, there are some
differences to keep in mind though.&lt;/p&gt;
&lt;h3 id="advantages_1"&gt;&lt;a class="toclink" href="#advantages_1"&gt;Advantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Most of the advantages of the HTML export (see disadvantages).&lt;/li&gt;
&lt;li&gt;Hosted online for free, can be shared with a link.&lt;/li&gt;
&lt;li&gt;It can be downloaded as .ipynb.&lt;/li&gt;
&lt;li&gt;Automatic support for MyBinder and Google Colab (See next sections).&lt;/li&gt;
&lt;li&gt;Support for version control out of the box as part of git.&lt;/li&gt;
&lt;li&gt;Works with public and private repositories and also in Github Enterprise.&lt;/li&gt;
&lt;li&gt;It is &lt;em&gt;discoverable&lt;/em&gt; by Github Search Engine&lt;/li&gt;
&lt;li&gt;Generate Repository-level analytics.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="disadvantages_1"&gt;&lt;a class="toclink" href="#disadvantages_1"&gt;Disadvantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Requires time to load the view, it may fail for extensive notebooks.&lt;/li&gt;
&lt;li&gt;Requires a Github account and familiarity with git in general.&lt;/li&gt;
&lt;li&gt;Requires readers to be somewhat familiar with Github UI.&lt;/li&gt;
&lt;li&gt;Mobile design is not optimal&lt;/li&gt;
&lt;li&gt;Has no cache mechanism, HTML views are computed each time.&lt;/li&gt;
&lt;li&gt;Not compatible with Analytics solutions like Google Analytics.&lt;/li&gt;
&lt;li&gt;Not compatible with interactive visualization tools like Altair or Plotly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use_1"&gt;&lt;a class="toclink" href="#when-to-use_1"&gt;When to use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ideal for people and teams already working with Github Repositories. If not
working with them, other options like Google Colab or NBViewer might be better.
Another possible scenario is when old versions of particular notebooks should
be re-visited, Github makes it easy and intuitive. Nonetheless, If cell
execution or interactive plots are necessary, this option is not suitable.&lt;/p&gt;
&lt;p&gt;Most Github &lt;a href="https://github.com/search?l=Jupyter+Notebook&amp;amp;q=notebook&amp;amp;type=Repositories" target="_blank"&gt;Repositories with Jupyter Notebooks&lt;/a&gt; 
can be used as examples (there were more than 66.000 at the
time of this writing). One popular instance is the &lt;a href="https://github.com/ctgk/PRML/tree/master/notebooks" target="_blank"&gt;Python implementation repository&lt;/a&gt; 
of the algorithms of the &lt;a href="https://github.com/ctgk/PRML/blob/master/notebooks/ch01_Introduction.ipynb" target="_blank"&gt;Pattern Recognition and Machine Learning by Christopher Bishop.&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="nbviewer-publishing"&gt;&lt;a class="toclink" href="#nbviewer-publishing"&gt;NBViewer Publishing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="/blog/images/jupyter-publishing/nbviewer.png"&gt;&lt;img alt="NBviewer" class="b-lazy" data-src="/blog/images/jupyter-publishing/nbviewer.png" src="https://elc.github.io/blog/images/jupyter-publishing/nbviewer-thumbnail.png" width="1496"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://nbviewer.jupyter.org/" target="_blank"&gt;NBviewer&lt;/a&gt; is a free, online
tool from the project Jupyter to display notebooks online. It combines two
Python packages, &lt;a href="https://nbconvert.readthedocs.io/en/latest/" target="_blank"&gt;NBconvert&lt;/a&gt; f
or notebook transformations and
&lt;a href="https://www.tornadoweb.org/en/stable/" target="_blank"&gt;Tornado&lt;/a&gt; as web
service.&lt;/p&gt;
&lt;p&gt;In this platform, notebooks are presented in HTML, the same way as with Github
but, the User Interface is much more minimalistic and it is not tightly
integrated with any version control system.&lt;/p&gt;
&lt;h3 id="advantages_2"&gt;&lt;a class="toclink" href="#advantages_2"&gt;Advantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Most of the advantages of the HTML export.&lt;/li&gt;
&lt;li&gt;Hosted online for free, can be shared with a link.&lt;/li&gt;
&lt;li&gt;It can be downloaded as .ipynb.&lt;/li&gt;
&lt;li&gt;Automatic support for MyBinder (See next sections).&lt;/li&gt;
&lt;li&gt;It does not require any background knowledge (e.g. as opposed to Github
  publishing).&lt;/li&gt;
&lt;li&gt;It caches results, load times are fast after the first load.&lt;/li&gt;
&lt;li&gt;The UI has less branded content and is minimal, ideal for focus.&lt;/li&gt;
&lt;li&gt;Can load notebooks from anywhere on the web, just with the URL.&lt;/li&gt;
&lt;li&gt;It can be seamlessly integrated with Github (Repositories and Gists).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="disadvantages_2"&gt;&lt;a class="toclink" href="#disadvantages_2"&gt;Disadvantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Mobile design is better than Github&lt;/li&gt;
&lt;li&gt;Because of its cache, results may take some time to refresh when updated.&lt;/li&gt;
&lt;li&gt;Not compatible with Analytics solutions like Google Analytics.&lt;/li&gt;
&lt;li&gt;Not compatible with interactive visualization tools like Altair or Plotly.&lt;/li&gt;
&lt;li&gt;No discoverability capabilities such as Github's.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use_2"&gt;&lt;a class="toclink" href="#when-to-use_2"&gt;When to use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This solution is similar to Github's, but it is a better fit for non-developer
users (e.g. mathematicians and statisticians may not have a background with
version control). Furthermore, it is commonly used for writing static books,
one of the most popular ones being
&lt;a href="https://camdavidsonpilon.github.io/Probabilistic-Programming-and-Bayesian-Methods-for-Hackers/" target="_blank"&gt;Probabilistic-Programming-and-Bayesian-Methods-for-Hackers&lt;/a&gt;. 
As well as other HTML-based approaches, If cell execution or
interactive plots are necessary, this option is not suitable.&lt;/p&gt;
&lt;h2 id="static-site-generator-integration"&gt;&lt;a class="toclink" href="#static-site-generator-integration"&gt;Static Site Generator Integration&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="/blog/images/jupyter-publishing/static-site-generators.png"&gt;&lt;img alt="Static Site Generators" class="narrow b-lazy" data-src="/blog/images/jupyter-publishing/static-site-generators.png" src="https://elc.github.io/blog/images/jupyter-publishing/static-site-generators-thumbnail.png" width="798"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nowadays, there is an increasing trend in popularity for Jamstack tools, i.e.
Static Site Generators. That is why there are plenty of options available in
the Python ecosystem (&lt;a href="https://jamstack.org/generators/"&gt;50 at the time of this writting&lt;/a&gt;){: target="_blank"}. 
That been said the most popular ones are &lt;a href="https://blog.getpelican.com/" target="_blank"&gt;Pelican&lt;/a&gt;, 
&lt;a href="https://www.getlektor.com/" target="_blank"&gt;Lektor&lt;/a&gt; and &lt;a href="https://getnikola.com/" target="_blank"&gt;Nikola&lt;/a&gt; 
based on Github Stars.&lt;/p&gt;
&lt;p&gt;From these three options, Nikola is the only one with &lt;a href="https://getnikola.com/handbook.html#supported-input-formats" target="_blank"&gt;native support&lt;/a&gt; for .ipynb files, whereas
&lt;a href="https://github.com/danielfrg/pelican-jupyter" target="_blank"&gt;Pelican&lt;/a&gt; and
&lt;a href="https://github.com/baldwint/lektor-jupyter" target="_blank"&gt;Lektor&lt;/a&gt; require
plugins, once installed their use should be straightforward.&lt;/p&gt;
&lt;p&gt;Another possibility is to use &lt;a href="https://fastpages.fast.ai/" target="_blank"&gt;FastPages&lt;/a&gt;, 
an static site generator thought specifically for Jupyter Notebooks by the
FastAI team. It is not as popular as the other three but it is raising in
popularity in the last couple of years.&lt;/p&gt;
&lt;p&gt;Independently of the particular generator, the advantages and disadvantages are
identical.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This approach is &lt;strong&gt;not&lt;/strong&gt; embedding Jupyter Notebooks in a static
site, but rather using the .ipynb file itself as the source. Embedding
notebooks is covered as one of the Executable solutions.&lt;/p&gt;
&lt;h3 id="advantages_3"&gt;&lt;a class="toclink" href="#advantages_3"&gt;Advantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;It provides the greatest level of customization and control by designing its
  templates&lt;/li&gt;
&lt;li&gt;It is compatible with Analytics solutions like Google Analytics. Should be
  added manually.&lt;/li&gt;
&lt;li&gt;It is compatible with interactive, HTML-based visualization tools like
  Altair. Most likely require some additional configuration.&lt;/li&gt;
&lt;li&gt;There are no dependencies on third parties&lt;/li&gt;
&lt;li&gt;The notebook is attached to the personal brand of the site and not "hosted in
  the platform everyone uses".&lt;/li&gt;
&lt;li&gt;Better discoverability through search engines when optimizing SEO.&lt;/li&gt;
&lt;li&gt;Readers do not see a Jupyter Notebook but a web page, without the structure
  of the cells, this produces a more article-like look and feel.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="disadvantages_3"&gt;&lt;a class="toclink" href="#disadvantages_3"&gt;Disadvantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;It requires a lot of setups manually. Static Gen, Templates, Plugins, etc.&lt;/li&gt;
&lt;li&gt;Usually, the deployment requires either a manual process or configuring a
  Continuous Integration / Deployment Pipeline, which can be done for free but
  configuring it is time-consuming.&lt;/li&gt;
&lt;li&gt;It creates &lt;em&gt;a whole site&lt;/em&gt;, which might be excessive for simple use cases.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use_3"&gt;&lt;a class="toclink" href="#when-to-use_3"&gt;When to use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This approach is more suitable for individuals and or organizations who want to
keep and maintain a website/blog and at the same time showcase jupyter
notebooks. It requires intermediate knowledge of software engineering and is
maybe not the most adequate solution for those coming from other fields. &lt;/p&gt;
&lt;p&gt;Furthermore, it assumes a continuous stream of new content rather than simple
seldom updated publications. All the discoverability capabilities of other
solutions are not included here, thus requiring additional work.&lt;/p&gt;
&lt;p&gt;That being said, this is the only solution where the writer has full control
over the implementation, the look and feel, and the UI in general, allowing to
use Analytics solutions as well as some interactivity.&lt;/p&gt;
&lt;h3 id="why-not-sphinx-mkdocs-cactus-or-x"&gt;&lt;a class="toclink" href="#why-not-sphinx-mkdocs-cactus-or-x"&gt;Why not Sphinx, MkDocs, Cactus, or X?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The idea behind publishing a Jupyter Notebook is different from software
documentation, which is the main focus for Sphinx and MkDocs. Cactus is another
popular alternative but its last commit was in 2017, making it obsolete. Other
static site generators are less known and at the time of this writing do not
present any meaningful integration with Jupyter Notebooks.&lt;/p&gt;
&lt;p&gt;A clarification should be made about Sphinx since it is used as the back-end
for another solution called Jupyter-book which will be cover below.&lt;/p&gt;
&lt;h2 id="jupyter-book-static"&gt;&lt;a class="toclink" href="#jupyter-book-static"&gt;Jupyter-Book - Static&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://jupyterbook.org/intro.html" target="_blank"&gt;Jupyter-Book&lt;/a&gt; is a
solution that can be used in Static, Executable, and printable scenarios,
however, the advantages and disadvantages of each are slightly different and
the level of maturity is not the same either. Therefore, in this article, it
will be repeated for each category.&lt;/p&gt;
&lt;p&gt;This tool has been &lt;a href="https://youtu.be/2Z7wDaYt53Y" target="_blank"&gt;migrated to the Python ecosystem&lt;/a&gt; 
(it used Ruby and Jekyll in the past), and although it is not extremely popular
at the moment, the project is gaining traction and seems it would be the new 
standard in the short-term&lt;/p&gt;
&lt;p&gt;As an additional resource for this article, a &lt;a href="https://github.com/ELC/jupyter-book-template-cookiecutter" target="_blank"&gt;template repository&lt;/a&gt;
to get started with Jupyter-Book was prepared, it works for
static, executable, and also printable scenarios and can help getting started.&lt;/p&gt;
&lt;h3 id="advantages_4"&gt;&lt;a class="toclink" href="#advantages_4"&gt;Advantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;It creates a self-contained output, giving consistency across the content&lt;/li&gt;
&lt;li&gt;It creates tables of contents automatically&lt;/li&gt;
&lt;li&gt;It is compatible with Analytics solutions like Google Analytics. Should be
  added manually.&lt;/li&gt;
&lt;li&gt;Many configuration options&lt;/li&gt;
&lt;li&gt;Support for bibliography&lt;/li&gt;
&lt;li&gt;Extended markup features via MyST&lt;/li&gt;
&lt;li&gt;Integration with Google Colab, MyBinder, and Thebe (see below sections)&lt;/li&gt;
&lt;li&gt;It is not necessary to execute the notebooks beforehand&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="disadvantages_4"&gt;&lt;a class="toclink" href="#disadvantages_4"&gt;Disadvantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;It creates a self-contained output, making it difficult to integrate with
  existing websites&lt;/li&gt;
&lt;li&gt;It is not possible to customize the theme out of the box.&lt;/li&gt;
&lt;li&gt;Usually, the deployment requires either a manual process or configuring a
  Continuous Integration / Deployment Pipeline, which can be done for free but
  configuring it is time-consuming.&lt;/li&gt;
&lt;li&gt;If using one of the advanced features of MyST, the notebook might be
  incorrectly display using any other solution shown here&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use_4"&gt;&lt;a class="toclink" href="#when-to-use_4"&gt;When to use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Despite having a "book" in the name, the actual layout is similar to modern
software documentation. The reason being the main theme is inspired by the
&lt;a href="https://pandas.pydata.org/pandas-docs/stable/user_guide/10min.html" target="_blank"&gt;pandas docs&lt;/a&gt;. 
If the content consists of several Jupyter Books that can be
ordered into sections, chapters, or a similar hierarchical structure,
Jupyter-Book is extremely useful&lt;/p&gt;
&lt;p&gt;As an example, the data visualization library Altair used this tool to build
their &lt;a href="https://altair-viz.github.io/altair-tutorial/" target="_blank"&gt;official tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="executable-solutions"&gt;&lt;a class="toclink" href="#executable-solutions"&gt;Executable Solutions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the previous sections, all solutions aimed at providing a static
representation of the notebook. That was the most convenient way to share a
notebook. Nevertheless, in some use cases, the content is required to be
executable. For example, for reproducibility results in a research review; or
to showcase to students what happens when the code changes in a pedagogical
setting.&lt;/p&gt;
&lt;p&gt;The fact that the notebook is executed means that the kernel should run on a
server and the input should be sent and the output should be fetched. There are
free servers that allow to do that but certainly with limitations or additional
steps for configuration.&lt;/p&gt;
&lt;p&gt;In this category, two backends will be shown: Google Colab and MyBinder. And
four different ways are presented on how to use them, two direct and two
indirect.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important Note:&lt;/strong&gt; The execution of the code will be always on a sandbox
environment, meaning that there are no risks of running insecure code, neither
for the writer or the reader.&lt;/p&gt;
&lt;h2 id="jupyter-lite"&gt;&lt;a class="toclink" href="#jupyter-lite"&gt;Jupyter Lite&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="/blog/images/jupyter-publishing/jupyter-lite.png"&gt;&lt;img alt="Static Site Generators" class="narrow b-lazy" data-src="/blog/images/jupyter-publishing/jupyter-lite.png" src="https://elc.github.io/blog/images/jupyter-publishing/jupyter-lite-thumbnail.png" width="900"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/jupyterlite/jupyterlite" target="_blank"&gt;Jupyter Lite&lt;/a&gt;
is a young (First commit on the 21st March 2021) yet popular tool (1.6k stars)
developed by the Jupyter team. The tool is still &lt;em&gt;unofficial&lt;/em&gt; as per their docs
but, managed to achieve something that was never done before: &lt;strong&gt;Jupyter in the Browser
without a Backend&lt;/strong&gt;. That means that having only a static server could bring a
whole Jupyter Notebook/Lab environment.&lt;/p&gt;
&lt;p&gt;This works thanks to &lt;a href="https://pyodide.org/en/stable/" target="_blank"&gt;Mozilla's Pyodide&lt;/a&gt;,
this other project ships the scientific Python stack compiled to WebAssembly
and thus a backend is not needed as everything happens in the front-end.&lt;/p&gt;
&lt;h3 id="advantages_5"&gt;&lt;a class="toclink" href="#advantages_5"&gt;Advantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;One of the most transparent experiences for Executable Jupyter Notebooks.&lt;/li&gt;
&lt;li&gt;It does not require a setup for the reader.&lt;/li&gt;
&lt;li&gt;The data is persisted to the browser localstorage.&lt;/li&gt;
&lt;li&gt;It has multiple kernels (Python and Javascript) support built-in.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="disadvantages_5"&gt;&lt;a class="toclink" href="#disadvantages_5"&gt;Disadvantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;It requires some setup for the writer.&lt;/li&gt;
&lt;li&gt;It is a Notebook-only environment, it does not integrate with the existing
  website or platform.&lt;/li&gt;
&lt;li&gt;Configuration is not as straightforward as with other solutions.&lt;/li&gt;
&lt;li&gt;It is still in Alpha, meaning breaking changes can be introduced without
  prior notice. And the performance might be unstable (crashes).&lt;/li&gt;
&lt;li&gt;Slower than solutions with a dedicated back-end.&lt;/li&gt;
&lt;li&gt;Since there is no dedicated Back-End, performance might be compromised in
  low-end PCs.&lt;/li&gt;
&lt;li&gt;Good with the defaults but, having a custom configuration may require
  additional setup.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use_5"&gt;&lt;a class="toclink" href="#when-to-use_5"&gt;When to use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For proofs of concepts without complex dependencies, good internet connection,
and modern hardware. This might be a great choice. Uses cases might be MOOCs or
other events where participants need Jupyter and no dedicated server is
provided.&lt;/p&gt;
&lt;p&gt;However, it is not recommended when a stable and robust solution is needed.&lt;/p&gt;
&lt;h2 id="embedded-solution"&gt;&lt;a class="toclink" href="#embedded-solution"&gt;Embedded Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="/blog/images/embed_interactive_notebooks/embed-interactive-notebooks_headerimage.png"&gt;&lt;img alt="Static Site Generators" class="b-lazy" data-src="/blog/images/embed_interactive_notebooks/embed-interactive-notebooks_headerimage.png" src="https://elc.github.io/blog/images/embed_interactive_notebooks/embed-interactive-notebooks_headerimage-thumbnail.png" width="1401"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Embedding a notebook means &lt;em&gt;inserting&lt;/em&gt; some input/output cells into an existing
web page (generally but not necessarily static). The aforementioned interaction
with the back-end is taken care of by
&lt;a href="https://www.nbinteract.com/" target="_blank"&gt;NBInteract&lt;/a&gt;, a python package
that was developed for this very purpose. In this blog, there is a &lt;a href="https://elc.github.io/posts/embed-interactive-notebooks/" target="_blank"&gt;brief tutorial&lt;/a&gt; 
explaining how to do this step by step&lt;/p&gt;
&lt;h3 id="advantages_6"&gt;&lt;a class="toclink" href="#advantages_6"&gt;Advantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;It is fully compatible with Jupyter Widgets (ipywidgets).&lt;/li&gt;
&lt;li&gt;There is full control about dependencies and environment.&lt;/li&gt;
&lt;li&gt;The user sees the execution inside the same page, no redirections are needed.&lt;/li&gt;
&lt;li&gt;It is fully integrated with MyBinder (see the section below).&lt;/li&gt;
&lt;li&gt;Several independent notebooks can be embedded in a single static page.&lt;/li&gt;
&lt;li&gt;It is compatible with Analytics solutions like Google Analytics. Should be
  added manually.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="disadvantages_6"&gt;&lt;a class="toclink" href="#disadvantages_6"&gt;Disadvantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Requires a Github account and basic use of git.&lt;/li&gt;
&lt;li&gt;The configuration should be done on a notebook by notebook basis.&lt;/li&gt;
&lt;li&gt;The user has to click a button and only then the process is triggered,
  leading to potential delays.&lt;/li&gt;
&lt;li&gt;The reader cannot modify the code, interactivity is limited to widgets&lt;/li&gt;
&lt;li&gt;The server that runs the code will be shut down after some minutes of
  inactivity.&lt;/li&gt;
&lt;li&gt;The user experience might be a little uncomfortable because one has to wait
  until the kernel is ready&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use_6"&gt;&lt;a class="toclink" href="#when-to-use_6"&gt;When to use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This approach resembles the "Flash Application" or the "Java Applet" where a
small piece of an external tool is embedded into a static website. In this
case, that external tool is a Jupyter notebook.&lt;/p&gt;
&lt;p&gt;One of the &lt;a href="https://elc.github.io/posts/ordinary-differential-equations-with-python/" target="_blank"&gt;articles of this blog&lt;/a&gt; 
uses this approach extensively to showcase Ordinary
Differential Equations with the aid of different ipywidgets.&lt;/p&gt;
&lt;p&gt;Although requiring some setup, it is one of the less disruptive approaches for
writers and readers alike.&lt;/p&gt;
&lt;h2 id="google-colaboratory"&gt;&lt;a class="toclink" href="#google-colaboratory"&gt;Google Colaboratory&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="/blog/images/jupyter-publishing/google-colab.png"&gt;&lt;img alt="Google Colab" class="b-lazy" data-src="/blog/images/jupyter-publishing/google-colab.png" src="https://elc.github.io/blog/images/jupyter-publishing/google-colab-thumbnail.png" width="1853"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://colab.research.google.com/notebooks/welcome.ipynb" target="_blank"&gt;Google Colaboratory&lt;/a&gt; 
or simply Colab is a service provided for free by Google that
comes with these main features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All commonly used data science libraries are pre-installed.&lt;/li&gt;
&lt;li&gt;It integrates seamlessly with Google Drive.&lt;/li&gt;
&lt;li&gt;It has support for GPU out of the box.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One of the interesting features is that any public Github repo can be opened
directly from Colab by changing the URL.&lt;/p&gt;
&lt;h3 id="advantages_7"&gt;&lt;a class="toclink" href="#advantages_7"&gt;Advantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Seemless import from Github.&lt;/li&gt;
&lt;li&gt;It does not require Github at all. Any user with a Google Gmail account can
  use it.&lt;/li&gt;
&lt;li&gt;Easy to share with a link.&lt;/li&gt;
&lt;li&gt;Easy to manage permissions, the same mechanism as Google Drive.&lt;/li&gt;
&lt;li&gt;It offers GPU support out of the box.&lt;/li&gt;
&lt;li&gt;New dependencies can be installed if needed, yet not automatically.&lt;/li&gt;
&lt;li&gt;Can read and write from Google Drive.&lt;/li&gt;
&lt;li&gt;URL replacement integration with Github.&lt;/li&gt;
&lt;li&gt;There are no set up times.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="disadvantages_7"&gt;&lt;a class="toclink" href="#disadvantages_7"&gt;Disadvantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The interface is custom from Google, it is different than the traditional
  Jupyter Lab.&lt;/li&gt;
&lt;li&gt;The user has to navigate to a different website to execute the notebook.&lt;/li&gt;
&lt;li&gt;If one closes the browser tab, the session is lost.&lt;/li&gt;
&lt;li&gt;The notebook kernel is shut down after some time of inactivity.&lt;/li&gt;
&lt;li&gt;The only possible storage is Google Drive, hence inheriting size limitations
  of the associated account (15GB at the time of this writing).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use_7"&gt;&lt;a class="toclink" href="#when-to-use_7"&gt;When to use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The fact that Colab offers GPU support is a game-changer, no other service does
it for free. Some teams may choose this solution solely because of this,
especially in deep learning applications.&lt;/p&gt;
&lt;h2 id="my-binder"&gt;&lt;a class="toclink" href="#my-binder"&gt;My Binder&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="/blog/images/jupyter-publishing/my-binder.png"&gt;&lt;img alt="Static Site Generators" class="b-lazy" data-src="/blog/images/jupyter-publishing/my-binder.png" src="https://elc.github.io/blog/images/jupyter-publishing/my-binder-thumbnail.png" width="1123"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://mybinder.org/" target="_blank"&gt;MyBinder&lt;/a&gt; or simply Binder is a free
online service that creates sandbox environments to run Jupyter. It has support
for both Jupyter Notebook and Jupyter Lab. However, it offers CPU-only
processing capabilities.&lt;/p&gt;
&lt;h3 id="advantages_8"&gt;&lt;a class="toclink" href="#advantages_8"&gt;Advantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;It is used as a base for many other services.&lt;/li&gt;
&lt;li&gt;New dependencies can be installed if needed automatically.&lt;/li&gt;
&lt;li&gt;No apparent limit for data while the session is alive.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="disadvantages_8"&gt;&lt;a class="toclink" href="#disadvantages_8"&gt;Disadvantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;It takes some time to build and run.&lt;/li&gt;
&lt;li&gt;The user has to navigate to a different website to execute the notebook.&lt;/li&gt;
&lt;li&gt;Configuring it for the first time might require some knowledge of Linux,
  Docker or Conda environments.&lt;/li&gt;
&lt;li&gt;The notebook kernel is shut down after some time of inactivity.&lt;/li&gt;
&lt;li&gt;There are no storage capabilities, the results should be manually downloaded.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use_8"&gt;&lt;a class="toclink" href="#when-to-use_8"&gt;When to use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MyBinder is a backbone service and for a notebook writer, it may not be that
useful since other services like Jupyter-book or the Embedded approach use it
under the hood. However, it is helpful to know some of the details of the
internals to see what is possible.&lt;/p&gt;
&lt;p&gt;The typical use case for bare Binder is to have a repo with a particularly
complicated setup of dependencies that cannot be used otherwise. For example,
using software requiring particular C libraries or certain operating system
libraries pre-installed (e.g. FFMPEG, Libpostal, etc.).&lt;/p&gt;
&lt;p&gt;A more concrete example is creating animations with matplotlib which requires
FFMPEG for some output formats, being FFMPEG not a Python library but 
software that should be installed on the Operating System level. The article on
&lt;a href="https://elc.github.io/posts/times-tables/" target="_blank"&gt;Times Tables&lt;/a&gt;
covers this precise problem&lt;/p&gt;
&lt;h2 id="jupyter-book-executable"&gt;&lt;a class="toclink" href="#jupyter-book-executable"&gt;Jupyter-Book - Executable&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned in the static section Jupyter-Book can be used for static and
executable content. In the case of executable content, it provides support for
three different services:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Google Colab&lt;/li&gt;
&lt;li&gt;MyBinder&lt;/li&gt;
&lt;li&gt;Thebe&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since Colab and Binder were already discussed, this section will focus on
&lt;a href="https://thebe.readthedocs.io/en/latest/" target="_blank"&gt;Thebe&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thebe is a service that acts as the embedded approach described above with the
difference is that it is integrated with Jupyter-book since both projects are
under the bigger &lt;a href="https://executablebooks.org/en/latest/" target="_blank"&gt;Executable Books Project&lt;/a&gt;, 
but it is not limited to Jupyter-Book. Thebe uses MyBinder as a back-end and 
provides an execution environment for static sites. &lt;/p&gt;
&lt;h3 id="advantages_9"&gt;&lt;a class="toclink" href="#advantages_9"&gt;Advantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;All of the advantages of using MyBinder&lt;/li&gt;
&lt;li&gt;The user sees the execution inside the same page, no redirections are needed.&lt;/li&gt;
&lt;li&gt;Seamless integration with Jupyter-book, no additional configuration needed.&lt;/li&gt;
&lt;li&gt;Full support for custom dependencies through MyBinder&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="disadvantages_9"&gt;&lt;a class="toclink" href="#disadvantages_9"&gt;Disadvantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The user experience might be a little uncomfortable because one has to wait
  until the kernel is ready&lt;/li&gt;
&lt;li&gt;Configuring without using Jupyter-book might require HTML/JS knowledge&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use_9"&gt;&lt;a class="toclink" href="#when-to-use_9"&gt;When to use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Thebe is a young project (223 Github stars at the moment of this writing) and
there is not a big collection of examples nor is it a well-known tool. However,
when used integrated with Jupyter-Book, it gives the reader the ability to
"suddenly being able to run the code examples" which is a great user
experience.&lt;/p&gt;
&lt;p&gt;At the moment, it is the ideal solution if already using Jupyter-Book, for a
similar approach using a more standalone tool, the embedded approach should be
preferred.&lt;/p&gt;
&lt;p&gt;As an additional resource for this article, a &lt;a href="https://github.com/ELC/jupyter-book-template-cookiecutter" target="_blank"&gt;template repository&lt;/a&gt;
to get started with Jupyter-Book was prepared, it works for
static, executable, and also printable scenarios and can help getting started.&lt;/p&gt;
&lt;h2 id="printable-solutions"&gt;&lt;a class="toclink" href="#printable-solutions"&gt;Printable Solutions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In some cases like academic publishing, book writing, or learning material the
preferred format is print paper. In this case, there are a variety of options
but the choice is not dependent on the technological feasibility but rather on
the target platform.&lt;/p&gt;
&lt;p&gt;If writing a book, a publisher will likely require a specific format, if going
self-publish, usually, only a PDF will be enough.&lt;/p&gt;
&lt;p&gt;In case of requiring AsciiDoc, Markdown, or ReStructuredText, Jupyter has
built-in options for exporting to these formats, then the particular publisher
instructions should be followed. Since this may vary significantly in each
case, this section will focus on the most used format of academia, LaTeX. LaTeX
is a special format that can be easily converted to PDF, therefore the term PDF
in this section will always refer to the LaTeX conversion to this format.&lt;/p&gt;
&lt;p&gt;Regardless of the approach taken, it is important to note that LaTeX can be
used for two purposes: articles and books. Typically articles are generated
from a single notebook file (not exclusively though) and books are a collection
of notebooks following a hierarchical structure.&lt;/p&gt;
&lt;p&gt;For books, specific book templates should be used to give the proper format,
including page numbers, headings, and such. That is why tools like
&lt;a href="https://www.overleaf.com/" target="_blank"&gt;Overleaf&lt;/a&gt; are recommended to
structure the document.&lt;/p&gt;
&lt;h2 id="built-in-export-latex"&gt;&lt;a class="toclink" href="#built-in-export-latex"&gt;Built-in Export: LaTeX&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The native LaTeX export will convert the notebook to the LaTeX format. This is
ideal for single file conversions and should be the preferred way to start
articles based on Jupyter Notebooks.&lt;/p&gt;
&lt;h3 id="advantages_10"&gt;&lt;a class="toclink" href="#advantages_10"&gt;Advantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The same notebooks can be used for static/executable printing, no
  printing-exclusive modifications are needed&lt;/li&gt;
&lt;li&gt;It is a native, straightforward solution.&lt;/li&gt;
&lt;li&gt;All images and figures are handled automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="disadvantages_10"&gt;&lt;a class="toclink" href="#disadvantages_10"&gt;Disadvantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;If using more than one notebook, each should be exported manually (can be
  automated with &lt;code&gt;nbconvert&lt;/code&gt; though).&lt;/li&gt;
&lt;li&gt;Usually, the code should be removed manually.&lt;/li&gt;
&lt;li&gt;It requires final editing on an external platform.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use_10"&gt;&lt;a class="toclink" href="#when-to-use_10"&gt;When to use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The built-in LaTeX export is suitable when dealing with single notebooks that
are not connected. It might be helpful to start an academic article but in such
media often the code should be removed. &lt;/p&gt;
&lt;p&gt;If the target is not an academic conference/journal or a publisher, other tools
like the static site generator or the other plain text, export might be more
suitable dependent on the particular use case.&lt;/p&gt;
&lt;h2 id="jupyter-book-for-printing"&gt;&lt;a class="toclink" href="#jupyter-book-for-printing"&gt;Jupyter-Book - For Printing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If already using Jupyter-Book, one possibility is to use the LaTeX target and
create a .tex with all the notebooks converted to LaTeX. This approach will
produce a consistent and book-like structured document. Some final formatting
might still be needed in third-party tools but it is much less work than the
default LaTeX export.&lt;/p&gt;
&lt;h3 id="advantages_11"&gt;&lt;a class="toclink" href="#advantages_11"&gt;Advantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The same notebooks can be used for static/executable printing, no
  printing-exclusive modifications are needed&lt;/li&gt;
&lt;li&gt;It combines multiple notebooks following a predefined structure.&lt;/li&gt;
&lt;li&gt;It can export multiple notebooks at the same time.&lt;/li&gt;
&lt;li&gt;It creates a numbered table of contents.&lt;/li&gt;
&lt;li&gt;It handles global bibliography.&lt;/li&gt;
&lt;li&gt;It supports basic PDF export.&lt;/li&gt;
&lt;li&gt;Can be integrated to generate a PDF on each commit.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="disadvantages_11"&gt;&lt;a class="toclink" href="#disadvantages_11"&gt;Disadvantages&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;The support is still experimental and might change.&lt;/li&gt;
&lt;li&gt;It requires configuring a CI/CD Pipeline.&lt;/li&gt;
&lt;li&gt;It requires final editing on an external platform.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use_11"&gt;&lt;a class="toclink" href="#when-to-use_11"&gt;When to use&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At the moment LaTeX and PDF are not the main focus of Jupyter-Book and the
design might appear basic, however, it is indeed a good starting point for
books. Using the tool for single notebooks might be excessive.&lt;/p&gt;
&lt;p&gt;As an additional resource for this article, a &lt;a href="https://github.com/ELC/jupyter-book-template-cookiecutter" target="_blank"&gt;template repository&lt;/a&gt;
to get started with Jupyter-Book was prepared, it works for
static, executable, and also printable scenarios and can help getting started.&lt;/p&gt;
&lt;p&gt;As an example, the official Jupyter-Book project generates a &lt;a href="https://github.com/executablebooks/jupyter-book/suites/3444456225/artifacts/81694222" target="_blank"&gt;PDF version of their docs&lt;/a&gt; in the form of a book, using 
the LaTeX export option in the middle&lt;/p&gt;
&lt;h2 id="honorable-mentions"&gt;&lt;a class="toclink" href="#honorable-mentions"&gt;Honorable Mentions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Some tools could be useful in some contexts but are not so widespread
as the ones presented so far.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://nbdev.fast.ai/" target="_blank"&gt;NBdev&lt;/a&gt;: is a tool developed by 
  the &lt;a href="https://www.fast.ai/" target="_blank"&gt;FastAI&lt;/a&gt; team and can be used
  to create Python libraries from Jupyter Notebooks. The whole FastAI framework
  is built with it. Not in the list because building libraries from notebooks
  is more of a niche application and the project is still very young (just a 
  few years). &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://fastai.github.io/fastdoc/" target="_blank"&gt;Fastdoc&lt;/a&gt;: also from 
  the &lt;a href="https://www.fast.ai/" target="_blank"&gt;FastAI&lt;/a&gt; team, it is a library
  to create publication ready books from Jupyter Notebooks. It was used to 
  write the &lt;a href="https://github.com/fastai/fastbook/" target="_blank"&gt;O'Reilly FastAI Book&lt;/a&gt;.
  Not in the list because the project is not currently active (Latest release 
  October 2020) and it is not as widespread as Jupyter-Book.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://starboard.gg/" target="_blank"&gt;Starboard&lt;/a&gt; is an online service
  that provides literal notebooks (not Jupyter) with Jupyter-like capabilities
  such as Code and Text cells. It runs completely on the browser (with Pyodide)
  and its goal is to make notebooks easier to share. Not in the list because it
  is its own format, not Jupyter (although Jupyter import is &lt;em&gt;possible&lt;/em&gt;), and
  because it is in early development.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://github.com/features/codespaces" target="_blank"&gt;Github Codespaces&lt;/a&gt;:
  is a Github project to work online in a Visual Studio Code hosted on the
  browser. At the time of this writing, it can be used in any repository by
  pressing "." (dot), one can navigate and edit the files with the free tier.
  To attach a compute instance, a paid service is offered to selected
  beta-tester organizations. Not in the list because it does not work with
  Jupyter out of the box and it only has a paid solution.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://cocalc.com/" target="_blank"&gt;Cocalc&lt;/a&gt;: a tool very similar to
  Google Colab but with a less powerful free tier plan. It does have unique
  features such as Chat Rooms and collaborative editing. Not in the list
  because there is a feature overlap with Colab and it is not as widespread. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://spell.ml/" target="_blank"&gt;Spell.ml&lt;/a&gt;: it is a service to provide
  workspaces to run Jupyter Notebooks. It has CPU support for free with
  additional paid GPU instances. Not in the list because it is not for
  publishing as only a single user has access to the notebooks but can be used
  to run long computational notebooks without needing the browser tab open as
  MyBinder or Colab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://datalore.jetbrains.com/" target="_blank"&gt;Datalore&lt;/a&gt;: the Jetbrains
  dedicated IDE for Jupyter Notebooks. It has some advantages as collaborative
  editing but it has only a limited amount of hours for the free plan. Not in the
  list because it is not an open-source solution and the policy of the free
  plan can change without notice.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Your suggestion&lt;/strong&gt;: if you want to add another solution to the list, send me
  an email with a brief description of the tool at castanoezequieleonardo at
  gmail.com&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="choose-the-best-tool"&gt;&lt;a class="toclink" href="#choose-the-best-tool"&gt;Choose the best tool&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To choose the best tool, look for the use case that best represents your needs
and see the available options&lt;/p&gt;
&lt;h3 id="i-need-gpu-support"&gt;&lt;a class="toclink" href="#i-need-gpu-support"&gt;I need GPU Support&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The only option is &lt;strong&gt;Colab&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="i-want-to-keep-my-readers-on-my-site"&gt;&lt;a class="toclink" href="#i-want-to-keep-my-readers-on-my-site"&gt;I want to keep my readers on my site&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Then use either the &lt;strong&gt;Embedded&lt;/strong&gt; or &lt;strong&gt;Thebe&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="i-need-analytics"&gt;&lt;a class="toclink" href="#i-need-analytics"&gt;I need Analytics&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use &lt;strong&gt;Jupyter-Book&lt;/strong&gt; or &lt;strong&gt;Embedded&lt;/strong&gt; approaches.&lt;/p&gt;
&lt;h3 id="i-need-cache-for-fast-load-time"&gt;&lt;a class="toclink" href="#i-need-cache-for-fast-load-time"&gt;I need Cache for fast load time&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use &lt;strong&gt;NBviewer&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id="i-want-to-create-a-portfolio-using-jupyter-notebooks"&gt;&lt;a class="toclink" href="#i-want-to-create-a-portfolio-using-jupyter-notebooks"&gt;I want to create a portfolio using Jupyter Notebooks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use a static site generator. This site was built using Pelican.&lt;/p&gt;
&lt;h3 id="i-have-a-very-specific-setup-of-dependencies"&gt;&lt;a class="toclink" href="#i-have-a-very-specific-setup-of-dependencies"&gt;I have a very specific setup of dependencies&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use any of the &lt;strong&gt;MyBinder-based&lt;/strong&gt; approaches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MyBinder&lt;/li&gt;
&lt;li&gt;Embedded&lt;/li&gt;
&lt;li&gt;Jupyter-Book&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are many different tools to publish Jupyter notebooks and whole tutorials
could be written about the features and possibilities of each. In this article,
the most compelling ones were summarized to help the notebook writer to decide
which tool is the most suitable for their use case.&lt;/p&gt;
&lt;p&gt;If any of the information presented is outdated, or you have suggestions for
new advantages or disadvantages of a particular solution please leave a comment
below.&lt;/p&gt;
&lt;p&gt;Below is a list of useful resources to continue learning and searching for
inspiration.&lt;/p&gt;
&lt;h2 id="additional-resources"&gt;&lt;a class="toclink" href="#additional-resources"&gt;Additional Resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Awesome Lists:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/jupyter/jupyter/wiki/a-gallery-of-interesting-jupyter-notebooks" target="_blank"&gt;Official Jupyter Gallery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/markusschanta/awesome-jupyter" target="_blank"&gt;Markusschanta (2.3k stars)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mauhai/awesome-jupyterlab" target="_blank"&gt;Mauhai (1.9k stars)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://executablebooks.org/en/latest/gallery.html" target="_blank"&gt;Gallery of Jupyter-Books&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Some Books built with Jupyter Notebooks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://camdavidsonpilon.github.io/Probabilistic-Programming-and-Bayesian-Methods-for-Hackers/" target="_blank"&gt;Probabilistic Programming &amp;amp; Bayesian Methods for Hackers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/thomas-haslwanter/statsintro_python" target="_blank"&gt;Introduction to Statistics with Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jakevdp/PythonDataScienceHandbook" target="_blank"&gt;Python Data Science Handbook&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Programming"></category><category term="Jupyter"></category><category term="Colab"></category><category term="Python"></category><category term="Notebooks"></category><category term="Binder"></category><category term="LaTeX"></category></entry><entry><title>Lyrics Presentation Generator</title><link href="https://elc.github.io/posts/online-lyrics-presentation-generator" rel="alternate"></link><published>2019-05-22T00:00:00-03:00</published><updated>2019-05-22T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2019-05-22:/posts/online-lyrics-presentation-generator</id><summary type="html">&lt;!-- Status: draft --&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/online-lyrics/online-lyrics-headerimage.png"&gt;&lt;img alt="Online Lyrics Presentation Generator Header Image" class="b-lazy" data-src="/blog/images/online-lyrics/online-lyrics-headerimage.png" src="https://elc.github.io/blog/images/online-lyrics/online-lyrics-headerimage-thumbnail.png" width="1920"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;More often than not I find myself writing power point presentations for Lyrics. This usually happens in the youth service at church and in christian camps. Since the process is quite repetitive and simple enough I consider developing a web app to generate this presentations automatically. In this article I …&lt;/p&gt;</summary><content type="html">&lt;!-- Status: draft --&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/online-lyrics/online-lyrics-headerimage.png"&gt;&lt;img alt="Online Lyrics Presentation Generator Header Image" class="b-lazy" data-src="/blog/images/online-lyrics/online-lyrics-headerimage.png" src="https://elc.github.io/blog/images/online-lyrics/online-lyrics-headerimage-thumbnail.png" width="1920"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;More often than not I find myself writing power point presentations for Lyrics. This usually happens in the youth service at church and in christian camps. Since the process is quite repetitive and simple enough I consider developing a web app to generate this presentations automatically. In this article I will show it how it works and how to use it.&lt;/p&gt;


&lt;h2 id="the-problem"&gt;&lt;a class="toclink" href="#the-problem"&gt;The Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As said in the introduction the problem is basically, avoid writing over an over the presentation for the lyrics&lt;/p&gt;
&lt;h2 id="the-solution"&gt;&lt;a class="toclink" href="#the-solution"&gt;The Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Developing a Web App to automatically generate the power point presentation. This app doesn't require any installation and will work from any browser, but for a better user experience it is recommended to use from a desktop/tablet environment. In this article, I will dedicate the next section to explain how to use it for non-technical users and then I will explain all its components from a technical perspective&lt;/p&gt;
&lt;p&gt;Note: I understand the importance of responsive design but to in this case in order to produce a presentation that match the text, bigger dimensions than the usual cellphone provides are needed. Besides, it is unlikely that the user will download the presentation from a mobile device.&lt;/p&gt;
&lt;h2 id="how-to-use-it"&gt;&lt;a class="toclink" href="#how-to-use-it"&gt;How to use it&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The app is available &lt;a href="https://elc.github.io/link/lyrics_presentation" target="_blank"&gt;online&lt;/a&gt;, as soon as you open it, you will see something like the following:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/online-lyrics/tutorial.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/online-lyrics/tutorial.png" src="https://elc.github.io/blog/images/online-lyrics/tutorial-thumbnail.png" width="1245"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the screen there are 3 main areas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Lyrics Area&lt;/strong&gt;: is the area marked in &lt;strong&gt;orange&lt;/strong&gt;, this is where the text of the lyrics will be written. To properly write the lyrics, one should follow the instructions (see below).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language Selection&lt;/strong&gt;: In the top right corner, there are two flags marked with &lt;strong&gt;green&lt;/strong&gt;, each flag changes the language of the whole page.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Buttons&lt;/strong&gt;: This area is marked with &lt;strong&gt;purple&lt;/strong&gt;, it includes two buttons, one for generating the presentation and the other to clear the text area.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="instructions-for-writing-the-lyrics"&gt;&lt;a class="toclink" href="#instructions-for-writing-the-lyrics"&gt;Instructions for writing the lyrics&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In order to write the lyrics, the following guide should be followed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Write each Verse with no blank lines in between.&lt;/li&gt;
&lt;li&gt;Separate Verses with blank lines.&lt;/li&gt;
&lt;li&gt;Separate Songs with three dashes, "---".&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The size of the Lyrics Area is set to match the resulting presentation so if the text fits well in the web page, it will fit in the presentation as well.&lt;/p&gt;
&lt;h2 id="how-it-works-technical"&gt;&lt;a class="toclink" href="#how-it-works-technical"&gt;How it works (Technical)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This web app is built using vanilla &lt;code&gt;HTML5&lt;/code&gt;, &lt;code&gt;CSS3&lt;/code&gt; and &lt;code&gt;Javascript&lt;/code&gt;. Additionally, a &lt;code&gt;Javascript&lt;/code&gt; library is used for creating the presentation, this library is &lt;a href="https://github.com/gitbrent/PptxGenJS" target="_blank"&gt;&lt;strong&gt;PptxGenJS&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;CSS&lt;/code&gt; is written inside the &lt;code&gt;HTML&lt;/code&gt; to avoid using another request, this is done because the whole style is about 100 lines and the whole app is contained in a single html file. The &lt;code&gt;Javascript&lt;/code&gt; is separated to keep logic and presentation layers separated.&lt;/p&gt;
&lt;p&gt;First I will show all the code and then split it into pieces and explain part by part&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;Javascript&lt;/code&gt; code to achieved this is the following:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;createPPT&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;PptxGenJS&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Presentation created with ELC&amp;#39;s Presentation Generator&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defineSlideMaster&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Template&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;bkgd&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;placeholder&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;100%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;100%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;align&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;center&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;fontSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;FFFFFF&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;fontFace&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Verdana&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;valign&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;middle&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;paraSpaceAfter&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;6&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;paraSpaceBefore&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;6&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;parseLyrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;verse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;verse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;---&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;createSlide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;createSlide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;verse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Presentation - Created with ELCs Presentation Generator&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parseLyrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[\r\n]{3,}/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;createSlide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;slide&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addNewSlide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Template&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;slide&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;clearText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;changeLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;localized&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;verse1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;verse2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;separator&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;verse1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;verse2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;verse3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="main-function"&gt;&lt;a class="toclink" href="#main-function"&gt;Main Function&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;createPPT&lt;/code&gt; function is the main function which is called whenever the "Generate Presentation" Button is clicked. It performs the following actions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create the presentation object.&lt;/li&gt;
&lt;li&gt;Set the Title.&lt;/li&gt;
&lt;li&gt;Define the template&lt;/li&gt;
&lt;li&gt;Extract the text&lt;/li&gt;
&lt;li&gt;Add each of the slides&lt;/li&gt;
&lt;li&gt;Save the file&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each of the actions is represented in one of the following lines. To keep it simple, the most complex tasks are explained in further detail below. The methods used for setting the title and saving are self explanatory.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;createPPT&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;PptxGenJS&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Presentation created with ELC&amp;#39;s Presentation Generator&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Template Definition&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Text Extraction&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Add Slide&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Presentation - Created with ELCs Presentation Generator&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="template-definition"&gt;&lt;a class="toclink" href="#template-definition"&gt;Template Definition&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In order to achieve a consistent style, a template should be used. In my own experience, black background with white letters gives the best results. To define a Template the method &lt;code&gt;defineSlideMaster&lt;/code&gt;. Its parameters corresponds to achieving slides with the following characteristics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Black Background Color: &lt;code&gt;bkgd: '000000'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Assing a unique title to use when creating the slide: &lt;code&gt;title: 'Template'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Give a unique identifier to a text element inside the slide: &lt;code&gt;name: 'body'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set the coordinates for the text element: &lt;code&gt;x: 0, y: 0,&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set the dimensions, both width and height: &lt;code&gt;w: "100%", h: "100%",&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Use a big font size: &lt;code&gt;fontSize: 44&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Use White color for the font: &lt;code&gt;color: 'FFFFFF'&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Center the text horizontally and vertically: &lt;code&gt;align: "center", valign: 'middle',&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set paragraph spacing: &lt;code&gt;paraSpaceAfter: '6', paraSpaceBefore: '6'&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When combining all the above and following the syntax provided by the official docs, the results is the following code:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Template Definition&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;defineSlideMaster&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Template&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bkgd&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;000000&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;placeholder&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;w&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;100%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;100%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;align&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;center&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fontSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;44&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;FFFFFF&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fontFace&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Verdana&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;valign&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;middle&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;paraSpaceAfter&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;6&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;paraSpaceBefore&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;6&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="text-extraction"&gt;&lt;a class="toclink" href="#text-extraction"&gt;Text Extraction&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Once the template is defined, the text should be extracted, to achieved this a very common practice is used in JS. Just referenced the element by a given ID and then extract its value. In this case the element is a TextArea defined in HTML5&lt;/p&gt;
&lt;p&gt;The resulting code is the following:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Text Extraction&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="add-slide"&gt;&lt;a class="toclink" href="#add-slide"&gt;Add Slide&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;After extracting the text, it should be parsed and then a new slide should be added for each verse.&lt;/p&gt;
&lt;p&gt;The parsing function returns a list of strings, each being either a verse or a &lt;code&gt;---&lt;/code&gt; which basically mean "Empty Slide". Both the &lt;code&gt;parseLyrics&lt;/code&gt; and the &lt;code&gt;createSlide&lt;/code&gt; are explained below.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add Slide&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nx"&gt;parseLyrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;verse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;verse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;---&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;createSlide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;createSlide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;verse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="parsing"&gt;&lt;a class="toclink" href="#parsing"&gt;Parsing&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;One would never know what the user would write, and, in order to support several languages (specially those with special characters), it is important to use a separator that works universally, in this case the blank line will separate two verses and the three dashes (---) will separate songs.&lt;/p&gt;
&lt;p&gt;In order to ignore several blank lines and then split a regular expression and then the &lt;code&gt;split&lt;/code&gt; method is used.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;parseLyrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/[\r\n]{3,}/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="create-slide"&gt;&lt;a class="toclink" href="#create-slide"&gt;Create Slide&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each slide will have a different text so to create a slide one should provide the engine (in this case the library &lt;code&gt;pptx&lt;/code&gt;) and the text to be inserted (the &lt;code&gt;text&lt;/code&gt; argument), then the new slide is created using the predefined template, after that the text in upper case is added using the placeholder defined in the template.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;createSlide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;slide&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pptx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addNewSlide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Template&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;slide&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toUpperCase&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;body&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="clear-text-button"&gt;&lt;a class="toclink" href="#clear-text-button"&gt;Clear Text Button&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In case the user wants to delete everything in the Lyrics Area, a button is provided, the functionality is overwriting the current content of the TextArea with an empty string.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;clearText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="localization"&gt;&lt;a class="toclink" href="#localization"&gt;Localization&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This extra feature provides client-side localization via &lt;a href="https://github.com/fabi1cazenave/webL10n" target="_blank"&gt;WebL10n&lt;/a&gt;, each string of the web app is both available in English and Spanish, but more languages could be added in the future if needed.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;changeLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;localized&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;verse1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;verse2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;separator&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;verse1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;verse2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;\n\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lyrics&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;webL10n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;verse3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Christianity"></category><category term="Christian"></category><category term="WebApp"></category><category term="Presentation"></category><category term="Lyrics"></category></entry><entry><title>Embed Interactive Jupyter Notebooks in Static Websites for Free</title><link href="https://elc.github.io/posts/embed-interactive-notebooks" rel="alternate"></link><published>2019-05-01T00:00:00-03:00</published><updated>2019-05-01T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2019-05-01:/posts/embed-interactive-notebooks</id><summary type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/embed_interactive_notebooks/embed-interactive-notebooks_headerimage.png"&gt;&lt;img alt="Embed Interactive Notebooks Logo" class="b-lazy" data-src="/blog/images/embed_interactive_notebooks/embed-interactive-notebooks_headerimage.png" src="https://elc.github.io/blog/images/embed_interactive_notebooks/embed-interactive-notebooks_headerimage-thumbnail.png" width="1401"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;After a lot of research on the internet, I found no practical tutorial explaining how to embed Jupyter Notebooks in Static Websites using only free technologies. I found a way to do it using Github Gists, MyBinder and NBInteract along with IPython Widgets and I want to share it so …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/embed_interactive_notebooks/embed-interactive-notebooks_headerimage.png"&gt;&lt;img alt="Embed Interactive Notebooks Logo" class="b-lazy" data-src="/blog/images/embed_interactive_notebooks/embed-interactive-notebooks_headerimage.png" src="https://elc.github.io/blog/images/embed_interactive_notebooks/embed-interactive-notebooks_headerimage-thumbnail.png" width="1401"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;After a lot of research on the internet, I found no practical tutorial explaining how to embed Jupyter Notebooks in Static Websites using only free technologies. I found a way to do it using Github Gists, MyBinder and NBInteract along with IPython Widgets and I want to share it so no one has to reinvent the wheel.&lt;/p&gt;


&lt;p&gt;This is a step by step guide to embed Jupyter Notebooks in a static website. There is also an &lt;a href="https://www.nbinteract.com/tutorial/tutorial_intro.html" target="_blank"&gt;official tutorial&lt;/a&gt; available in the docs.&lt;/p&gt;
&lt;p&gt;This guide will cover some points that aren't fully explained in the official tutorial, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use Gists instead of Repositories&lt;/li&gt;
&lt;li&gt;Reduce the size of the output HTML&lt;/li&gt;
&lt;li&gt;Specify dependencies for Binder&lt;/li&gt;
&lt;li&gt;Use only some cells and insert them in a blog post via IFrames&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="motivation"&gt;&lt;a class="toclink" href="#motivation"&gt;Motivation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I really like using Jupyter Notebooks for my experiments and I also like to show them in this blog, which is a pure static website built with Pelican. The problem emerged when I wanted to embed some interactive content from the notebook in the website, I thought this should have been solved long ago but it wasn't or at least it wasn't as Public as it should be.&lt;/p&gt;
&lt;p&gt;Having the possibility to embed Jupyter notebooks in a static website provides lots of advantages, just to mention a few:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Visitors don't need to leave the site in other to see the notebook.&lt;/li&gt;
&lt;li&gt;Visitors can actually interact with the code and see the results live even without knowing how to program.&lt;/li&gt;
&lt;li&gt;You can provide a quick way to show the results with prior and posterior explanations without writing everything in a notebook.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-tech-stack"&gt;&lt;a class="toclink" href="#the-tech-stack"&gt;The Tech Stack&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In order to do this, I used a set of tools. This is my personal choice but I believed is appropriate, of course, if you have any suggestions, feel free to write a comment below.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Github Gists&lt;/strong&gt;: To host the code and provide isolation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NBInteract&lt;/strong&gt;: To communicate with a JupyterHub Server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IPython Widgets&lt;/strong&gt;: To give interactivity to the notebook.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MyBinder&lt;/strong&gt;: To provide a server for the computations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key component here is &lt;strong&gt;NBInteract&lt;/strong&gt; but the other tools were necessary too.&lt;/p&gt;
&lt;p&gt;First, I want to clarify my workflow:&lt;/p&gt;
&lt;p&gt;I want to write an isolated notebook that the user could run via Binder &lt;strong&gt;(1)&lt;/strong&gt;, I want to write a blog post about what I've done in that notebook &lt;strong&gt;(2)&lt;/strong&gt; and in the post, I want to insert specific cells when appropriate &lt;strong&gt;(3)&lt;/strong&gt;. Additionally, I want my experiments pieces (the specific cells inserted) to be sharable, meaning any could embed them easily in their website &lt;strong&gt;(4)&lt;/strong&gt; and I also want to track how many times they were used and from which source &lt;strong&gt;(5)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;These 5 objectives are accomplished in the following way:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Since my experiments are usually independent of each other, I host them in &lt;strong&gt;Github Gist&lt;/strong&gt; instead of repositories. I believe it makes no sense to have a one-file Repo without a very sound reason.&lt;/li&gt;
&lt;li&gt;I use &lt;strong&gt;Pelican&lt;/strong&gt; to write the post but you can use whichever tool you are used to. &lt;em&gt;I know one could write posts inside Jupyter Notebooks themselves, even books have been written this way. But for consistency reasons, I want all my posts to be in Markdown.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NBInteract&lt;/strong&gt; is used to insert specific cells in the post. A little modification is needed to make it work with Gists instead of repositories.&lt;/li&gt;
&lt;li&gt;Everything above should be contained in a single HTML file and embedded through an &lt;strong&gt;IFrame&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Integrate &lt;strong&gt;Google Analytics&lt;/strong&gt; in the HTML from the previous step and add a filtered view in the admin panel to have a dedicated dashboard for this IFrames.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The full process could be separated into the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Environment Setup&lt;/li&gt;
&lt;li&gt;Gist Creation&lt;/li&gt;
&lt;li&gt;IFrame Creation&lt;/li&gt;
&lt;li&gt;Testing and Adaptation&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="1-environment-setup"&gt;&lt;a class="toclink" href="#1-environment-setup"&gt;1. Environment Setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First thing first, you need a fully working notebook. It should run all cells without errors in your local machine.&lt;/p&gt;
&lt;p&gt;In order to take full advantage of this methodology make sure you use widgets (such as IPython's) to give control to the user. Don't rely on manually changing variables inside cells but rather provide a user-friendly interface with buttons and sliders, this will result in a much more pleasant and useful UX/UI for the reader of your blog. Besides, this way, the reader doesn't have to know programming at all!&lt;/p&gt;
&lt;p&gt;When you have that done, you have to identify the notebook dependencies. It could be either from Conda, pip, apt or anywhere else.&lt;/p&gt;
&lt;p&gt;There are basically four ways you can specify the dependencies for &lt;strong&gt;Binder&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;requirements.txt&lt;/code&gt;: only suitable for pypi-only dependencies&lt;/li&gt;
&lt;li&gt;&lt;code&gt;environment.yml&lt;/code&gt;: better for Conda dependencies and pypi dependencies&lt;/li&gt;
&lt;li&gt;&lt;code&gt;apt.txt&lt;/code&gt;: only option to specify apt dependencies.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dockerfile&lt;/code&gt;: specify not only the dependencies but the whole OS.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The most common approach to work with Binder is a combination of &lt;code&gt;environment.yml&lt;/code&gt; and &lt;code&gt;apt.txt&lt;/code&gt;. Requirements.txt usually provide very little support for customization and dockerfile is discourage from the Binder developers themselves and should only be used when no other option worked.&lt;/p&gt;
&lt;p&gt;A more detailed explanation which many other ways can be found in the &lt;a href="https://mybinder.readthedocs.io/en/latest/sample_repos.html" target="_blank"&gt;official docs&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="2-gist-creation"&gt;&lt;a class="toclink" href="#2-gist-creation"&gt;2. Gist Creation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Gists are like small repositories, they have a sort of version control called "Revisions" but there are no branches, they provide simple updates one after the other. They are especially useful for cases where a repository is too much and just a few files are needed.&lt;/p&gt;
&lt;p&gt;Here I will explain how to create a Gist in Github, in case you already know it, you can skip to the &lt;a href="#dependency-management"&gt;next section&lt;/a&gt;, where I explain how to set the dependencies for Binder.&lt;/p&gt;
&lt;h3 id="creating-a-gist"&gt;&lt;a class="toclink" href="#creating-a-gist"&gt;Creating a Gist&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In order to create a Gist, you have to first have a Github Account.&lt;/p&gt;
&lt;p&gt;Once logged in, you have to click on your profile image in the top bar&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/embed_interactive_notebooks/gist_tutorial_01.png"&gt;&lt;img alt="Gist Tutorial Part 1" class="b-lazy" data-src="/blog/images/embed_interactive_notebooks/gist_tutorial_01.png" src="https://elc.github.io/blog/images/embed_interactive_notebooks/gist_tutorial_01-thumbnail.png" width="1284"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now select "Your Gists"&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/embed_interactive_notebooks/gist_tutorial_02.png"&gt;&lt;img alt="Gist Tutorial Part 2" class="narrow b-lazy" data-src="/blog/images/embed_interactive_notebooks/gist_tutorial_02.png" src="https://elc.github.io/blog/images/embed_interactive_notebooks/gist_tutorial_02-thumbnail.png" width="173"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The next page will change if you already have gists created but the top bar will remain the same, in the top bar select the "+" icon&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/embed_interactive_notebooks/gist_tutorial_03.png"&gt;&lt;img alt="Gist Tutorial Part 3" class="b-lazy" data-src="/blog/images/embed_interactive_notebooks/gist_tutorial_03.png" src="https://elc.github.io/blog/images/embed_interactive_notebooks/gist_tutorial_03-thumbnail.png" width="1280"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now you are in the Gist creation Template, here you have to write the Gist Name, the filename of the first file, its contents and you can additionally add files if necessary with the button below. When everything is set up, click in create public gist.&lt;/p&gt;
&lt;p&gt;Note: You can also create private gists for free but for NBInteract and thus this guide to work, the gist should be public.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/embed_interactive_notebooks/gist_tutorial_04.png"&gt;&lt;img alt="Gist Tutorial Part 4" class="b-lazy" data-src="/blog/images/embed_interactive_notebooks/gist_tutorial_04.png" src="https://elc.github.io/blog/images/embed_interactive_notebooks/gist_tutorial_04-thumbnail.png" width="1366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="dependency-management"&gt;&lt;a class="toclink" href="#dependency-management"&gt;Dependency Management&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You have to create a Github Gist and upload all the files needed, namely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The repo/repository file (.ipynb files)&lt;/li&gt;
&lt;li&gt;The dependencies files (requirements.txt, environment.yml, apt.txt, dockerfile)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once the gist is created, it should be tested with &lt;a href="https://mybinder.org/" target="_blank"&gt;MyBinder&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In order to test it first select the Combo Box in the main page&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/embed_interactive_notebooks/mybinder_tutorial_01.png"&gt;&lt;img alt="MyBinder Tutorial Part 1" class="narrow b-lazy" data-src="/blog/images/embed_interactive_notebooks/mybinder_tutorial_01.png" src="https://elc.github.io/blog/images/embed_interactive_notebooks/mybinder_tutorial_01-thumbnail.png" width="880"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Then select the Gist Option&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/embed_interactive_notebooks/mybinder_tutorial_02.png"&gt;&lt;img alt="MyBinder Tutorial Part 2" class="narrow b-lazy" data-src="/blog/images/embed_interactive_notebooks/mybinder_tutorial_02.png" src="https://elc.github.io/blog/images/embed_interactive_notebooks/mybinder_tutorial_02-thumbnail.png" width="907"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And finally, write the &lt;code&gt;Username/GISTID&lt;/code&gt; in the textbox and then click on "Launch"&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/embed_interactive_notebooks/mybinder_tutorial_03.png"&gt;&lt;img alt="MyBinder Tutorial Part 3" class="narrow b-lazy" data-src="/blog/images/embed_interactive_notebooks/mybinder_tutorial_03.png" src="https://elc.github.io/blog/images/embed_interactive_notebooks/mybinder_tutorial_03-thumbnail.png" width="873"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The first time you launch could take several minutes because it's building a docker image, this process is repeated each time you change the Gist so it is a good idea to always run your gists on Binder after you made a change.&lt;/p&gt;
&lt;p&gt;If the build was successful, open the notebook and run all the cells, check for errors, fix them until none appear and then continue to the next step.&lt;/p&gt;
&lt;p&gt;This step might seem to be pretty easy but there are cases (especially when doing interesting things) that may require additional settings, for example, setting the FFMPEG dependency correctly for creating animations and videos.&lt;/p&gt;
&lt;p&gt;You can check some of my personal examples of Gists:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/link/ode_python_gist" target="_blank"&gt;ODE with Python&lt;/a&gt; (environment.yml)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://elc.github.io/link/pascal_triangle_gist" target="_blank"&gt;Pascal Triangle Visualization&lt;/a&gt; (environment.yml + apt.txt)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this step completed, you can add a Binder Badge in your post directly to the notebook. Although the main objective is to embed specific parts, it doesn't imply the user wouldn't want access to the whole notebook in a more familiar environment such as the one Binder Provides.&lt;/p&gt;
&lt;p&gt;Example of a binder Badge (it leads to the a Notebook about Ordinary Differential Equations):&lt;/p&gt;
&lt;p&gt;&lt;a href="https://elc.github.io/link/ode_python_binder" target="_blank"&gt;&lt;img alt="Binder" class="narrow" src="https://mybinder.org/badge_logo.svg" width="109"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="3-iframe-creation"&gt;&lt;a class="toclink" href="#3-iframe-creation"&gt;3. IFrame Creation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the most important part and where &lt;strong&gt;NBInteract&lt;/strong&gt; comes in. For all the previous steps we used online tools such as &lt;strong&gt;Github Gists&lt;/strong&gt; and &lt;strong&gt;MyBinder&lt;/strong&gt;. But for this step, &lt;code&gt;nbinteract&lt;/code&gt; should be install.&lt;/p&gt;
&lt;h3 id="installation"&gt;&lt;a class="toclink" href="#installation"&gt;Installation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These are the installation instructions:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nbinteract&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

#&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;The&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;two&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;can&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;skipped&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;notebook&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;.&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;above&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nv"&gt;jupyter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nbextension&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;prefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;widgetsnbextension&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="nv"&gt;jupyter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;nbextension&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;prefix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;bqplot&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The steps for the installation could be found in its &lt;a href="https://github.com/SamLau95/nbinteract" target="_blank"&gt;official repo&lt;/a&gt;, make sure to check it in case there is an update.&lt;/p&gt;
&lt;h3 id="usage"&gt;&lt;a class="toclink" href="#usage"&gt;Usage&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The nbinteract is a command line application (CLI), so first navigate to the directory where the notebook file is and then run:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;nbinteract {notebook_filename}.ipynb -s {GitHub_UserName}/{Gist_ID}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will create an HTML file with the same filename of the notebook, but as mentioned earlier, the current version of NBInteract (0.2.4 when writing this) only supports Github &lt;em&gt;Repositories&lt;/em&gt; and not &lt;em&gt;Gists&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To fix this problem, just open the HTML file and look for this snippet (it should be at the end of the file):&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setupNbinteract&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// If NbInteract hasn&amp;#39;t loaded, wait one second and try again&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NbInteract&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setupNbinteract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;interact&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NbInteract&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{GitHub_UserName}/{Gist_ID}/master&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://mybinder.org&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gh&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interact&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;interact&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Only a small change is needed, change the &lt;strong&gt;&lt;code&gt;provider&lt;/code&gt;&lt;/strong&gt; from &lt;strong&gt;&lt;code&gt;gh&lt;/code&gt;&lt;/strong&gt; to &lt;strong&gt;&lt;code&gt;gist&lt;/code&gt;&lt;/strong&gt;. It should be something like this:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;setupNbinteract&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// If NbInteract hasn&amp;#39;t loaded, wait one second and try again&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NbInteract&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;setupNbinteract&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;interact&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NbInteract&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;spec&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{GitHub_UserName}/{Gist_ID}/master&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://mybinder.org&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gist&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prepare&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;interact&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;interact&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})()&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="adjustments"&gt;&lt;a class="toclink" href="#adjustments"&gt;Adjustments&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now the file is already prepared to be embedded as an HTML IFrame, but although that's technically true, we might want to make other adjustments:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a valid HTML5 document (some closing tags may be missing).&lt;/li&gt;
&lt;li&gt;Reduce the size of the file (by default they are quite big).&lt;/li&gt;
&lt;li&gt;Use only a subset of cells and not the whole notebook.&lt;/li&gt;
&lt;li&gt;Add a tracking system.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="html5"&gt;&lt;a class="toclink" href="#html5"&gt;HTML5&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The first adjustment is for improving SEO and compatibility, it will depend on every particular case as each notebook may need its own little changes. The W3C has an &lt;a href="https://validator.w3.org/#validate_by_input" target="_blank"&gt;online validator&lt;/a&gt; to check for Markup errors and warnings &lt;/p&gt;
&lt;h4 id="size"&gt;&lt;a class="toclink" href="#size"&gt;Size&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The second adjustment is needed since nbinteract inserts &lt;strong&gt;Bootstrap&lt;/strong&gt; and &lt;strong&gt;Font Awesome&lt;/strong&gt; by default in the HTML, you can check it because the &lt;code&gt;style&lt;/code&gt; tag covers approximately a &lt;strong&gt;95%&lt;/strong&gt; of the file. With custom styles and a careful selection of CSS classes, one can reduce the size pretty significantly. In my own experience, I manage to reduce from 14000 lines to 400 (318KB to 25KB), this is a reduction of the &lt;strong&gt;90%&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;Of course it may vary from user to user but since file size is crucial for a good user experience, I recommend to tweak and adapt the file to be as little as possible, and remember to use CSS in style tags and not relying on the website general CSS, this would be the only way to provide the same &lt;em&gt;look and feel&lt;/em&gt; when the file is used as an IFrame. This way each file will be completely independent of each other.&lt;/p&gt;
&lt;h4 id="specific-cells"&gt;&lt;a class="toclink" href="#specific-cells"&gt;Specific Cells&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The third adjustment is more of a hack actually. NBInteract is designed so that the user would use the notebook as the entire page but if the notebook contains just some cells (each with the proper imports), one can create minimal notebooks and insert them individually in a larger pure HTML page&lt;/p&gt;
&lt;p&gt;Just use nbinteract with a notebook file containing only the cells you are interested in. This will naturally lead to having as many .ipynb files as a group of cells you want to embed, each with an associated HTML file. It isn't a good idea to have everything in a big Notebook but neither is to have dozens of little notebooks. I believe a reasonable amount would be between 5 and 10.&lt;/p&gt;
&lt;h4 id="tracking-system"&gt;&lt;a class="toclink" href="#tracking-system"&gt;Tracking System&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;The fourth and last adjustment will depend on the tracking system of your choice but generally, it implies adding some script tag at the end of the file with a specific tracking ID. But &lt;strong&gt;DO NOT add the system yet!&lt;/strong&gt; Let's test it and then add it to avoid meaningless analytics &lt;em&gt;(unless you've added your IP as an exception in the Tracking System)&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="4-testing-and-adaptation"&gt;&lt;a class="toclink" href="#4-testing-and-adaptation"&gt;4. Testing and Adaptation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Lastly, you should embed the IFrame in your website and test it, here is where you should modify the styles according to the general aesthetics of the page and check if all works as desired. Make sure the IFrame size is correct for its content (avoid scrollbars)&lt;/p&gt;
&lt;p&gt;You can also test whether you want the input cells to be visible or only let the output to be rendered.&lt;/p&gt;
&lt;p&gt;After everything is tested, you can now add the tracking ID for the Analytics service (Google Analytics or the one of your choice)&lt;/p&gt;
&lt;p&gt;To make your IFrame easier to share, add an HTML snippet to specify how to embed your IFrame in other pages, see the examples below.&lt;/p&gt;
&lt;h2 id="examples"&gt;&lt;a class="toclink" href="#examples"&gt;Examples&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can find some examples in the official docs but I've also built some that you may find interesting. You can check the following posts to see them:&lt;/p&gt;
&lt;h3 id="ordinary-differential-equations"&gt;&lt;a class="toclink" href="#ordinary-differential-equations"&gt;Ordinary Differential Equations&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use NBInteract to numerically integrate several types of differential equations (including systems of ODEs) and change the parameters with sliders and see the results live.&lt;/p&gt;
&lt;div class="iframe-container" style="padding-top: 97%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/ode-python/foxes-rabbits-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;If you want to embed this widget in your website, just add the following HTML:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://elc.github.io/blog/iframes/ode-python/foxes-rabbits-iframe.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Read the &lt;a href="https://elc.github.io/posts/ordinary-differential-equations-with-python" target="_blank"&gt;Full Article&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="circular-times-table"&gt;&lt;a class="toclink" href="#circular-times-table"&gt;Circular Times Table&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use NBInteract to produce a video with matplotlib animation and FFmpeg. The user can create an image and a video with the set of parameters of their choice and then save them.&lt;/p&gt;
&lt;div class="iframe-container" style="padding-top: 101%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/times-tables/times-table-line-by-line-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;If you want to embed this widget in your website, just add the following HTML:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://elc.github.io/blog/iframes/times-tables/times-table-line-by-line-iframe.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Read the &lt;a href="https://elc.github.io/posts/times-tables" target="_blank"&gt;Full Article&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="additional-resources"&gt;&lt;a class="toclink" href="#additional-resources"&gt;Additional resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In case you want to go deeper, here are some useful resources:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/SamLau95/nbinteract" target="_blank"&gt;NBInteract Official Repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nbinteract.com/" target="_blank"&gt;NBInteract Official Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitter.im/nbinteract/Lobby/" target="_blank"&gt;NBInteract Gitter Channel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=jln6h-dE2-0" target="_blank"&gt;JupyterCon Talk from the creators of NBInteract&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www2.eecs.berkeley.edu/Pubs/TechRpts/2018/EECS-2018-57.pdf" target="_blank"&gt;NBInteract: Official Technical Report&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other resources to achieve similar things are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://nbdime.readthedocs.io/en/latest/" target="_blank"&gt;NBDime&lt;/a&gt;: Tool to work with git and Jupyter Notebook for easy Diff&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jupyter.org/jupyter-book/intro.html" target="_blank"&gt;JupyterBook&lt;/a&gt;: This tool also integrates executable and interactive notebook cells but rather than embedding them into a webpage, it creates the whole website. Alternative to GitBook&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/quantstack/voila" target="_blank"&gt;Voila&lt;/a&gt;: Interactive renderer for creating Dashboards&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sagecell.sagemath.org/" target="_blank"&gt;SageMathCell&lt;/a&gt;: A way to generate embeddings online for cells of notebooks. It supports Sage, Gap, GP, HTML, Maculay2, Maxima, Octave, Python, R and Singular&lt;/li&gt;
&lt;li&gt;&lt;a href="https://thebelab.readthedocs.io/en/latest/" target="_blank"&gt;ThebeLab&lt;/a&gt;: Thebe Lab turns your static HTML pages into interactive ones, powered by a kernel. It is an experiment attempting to rebuild Thebe with javascript APIs provided by JupyterLab.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/markusschanta/awesome-jupyter" target="_blank"&gt;Awesome Jupyter&lt;/a&gt;: A curated list of awesome Jupyter projects, libraries and resources.&lt;/li&gt;
&lt;/ul&gt;</content><category term="Programming"></category><category term="Python"></category><category term="Jupyter"></category><category term="NBinteract"></category><category term="Static Website"></category></entry><entry><title>Introductory Guide to Git with Visual Interface</title><link href="https://elc.github.io/posts/git-guide-with-visual-interface" rel="alternate"></link><published>2019-04-24T00:00:00-03:00</published><updated>2019-04-24T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2019-04-24:/posts/git-guide-with-visual-interface</id><summary type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/git-guide-with-visual-interface-headerimage.png"&gt;&lt;img alt="Git Tutorial Header Image" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/git-guide-with-visual-interface-headerimage.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/git-guide-with-visual-interface-headerimage-thumbnail.png" width="2000"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;As a Systems Engineering student, on successive occasions, I came across version control systems (VCS for short), sometimes from subjects related to programming and other in subjects related to software engineering.&lt;/p&gt;
&lt;p&gt;Remembering that when I had to learn all these concepts (especially how Git works), I went through several difficulties …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/git-guide-with-visual-interface-headerimage.png"&gt;&lt;img alt="Git Tutorial Header Image" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/git-guide-with-visual-interface-headerimage.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/git-guide-with-visual-interface-headerimage-thumbnail.png" width="2000"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;As a Systems Engineering student, on successive occasions, I came across version control systems (VCS for short), sometimes from subjects related to programming and other in subjects related to software engineering.&lt;/p&gt;
&lt;p&gt;Remembering that when I had to learn all these concepts (especially how Git works), I went through several difficulties, I decided to make an introductory guide with basic concepts of Git and how to use it through software with a visual interface.&lt;/p&gt;


&lt;p&gt;Personally, I think that to begin with, using a visual interface can be useful and didactic, however, I share the idea that understanding how the tool works from the console is fundamental for a deeper understanding of the concepts.&lt;/p&gt;
&lt;p&gt;This tutorial will summarize the main features of a particular software called GitKraken, that I personally think is the best. This guide isn't intended in any way to be exhaustive or detailed in all the functions of GitKraken, it will rather give the user the basic knowledge so that they can use the tool and gradually explore the other features on their own.&lt;/p&gt;
&lt;p&gt;&lt;a href="#additional-features"&gt;At the end of the document&lt;/a&gt; some of the advanced features of Git are detailed so that the user can know what those are and what is their purpose.&lt;/p&gt;
&lt;p&gt;This guide have independent sections so I leave the table of contents below in case you want to skip to a particular section&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#introduction-to-git"&gt;Introduction to Git&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#areas-in-git"&gt;Areas in Git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#stage-vs-commit"&gt;Stage vs Commit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#remote-repositories"&gt;Remote Repositories&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#branches"&gt;Branches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#additional-software"&gt;Additional Software&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#fork-of-a-repository"&gt;Fork of a repository&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#1-find-the-original-repository"&gt;1. Find the original repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#2-perform-fork"&gt;2. Perform Fork&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#clone-a-repository"&gt;Clone a repository&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#1-create-a-repository"&gt;1. Create a repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#1-alternative-create-a-repository"&gt;1 (Alternative). Create a repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#2-complete-the-necessary-information"&gt;2. Complete the necessary information&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#3-get-repository-url"&gt;3. Get Repository URL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#4-we-open-the-window-of-clone-inside-the-gitkraken"&gt;4. We open the window of Clone inside the GitKraken&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#4-alternative-1-we-open-the-clone-window-inside-the-gitkraken"&gt;4 (Alternative 1). We open the Clone window inside the GitKraken&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#4-alternative-2-we-open-the-clone-window-inside-the-gitkraken"&gt;4 (Alternative 2). We open the Clone window inside the GitKraken&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#5-paste-the-url"&gt;5. Paste the URL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#5-notification-of-success"&gt;5. Notification of Success&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#open-a-repository"&gt;Open a repository&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#1-open-window"&gt;1. Open Window&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#1-alternative-1-open-window"&gt;1 (Alternative 1). Open Window&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#1-alternative-2-open-window"&gt;1 (Alternative 2). Open Window&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#2-select-the-repository"&gt;2. Select the repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#3-select-the-folder"&gt;3. Select the folder&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#interface-elements"&gt;Interface Elements&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#basic-interface"&gt;Basic interface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#commits-and-branches-tree"&gt;Commits and Branches Tree&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#add-changes"&gt;Add Changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#synchronization-with-remote-repositories"&gt;Synchronization with remote repositories&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#download-changes-from-the-remote-repository"&gt;Download changes from the remote repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#upload-changes-to-the-remote-repository"&gt;Upload changes to the remote repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#example-of-fetch-and-pull"&gt;Example of Fetch and Pull&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#working-in-multiple-branches"&gt;Working in multiple branches&lt;/a&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href="#create-branch"&gt;Create Branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#join-branches-merge"&gt;Join Branches (Merge)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#erase-branch"&gt;Erase Branch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#pull-requests"&gt;Pull Requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#additional-features"&gt;Additional Features&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="introduction-to-git"&gt;&lt;a class="toclink" href="#introduction-to-git"&gt;Introduction to Git&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Git is a version control system (VCS) technology, it arises as an alternative to SVN, Hg, and TFS and its original purpose was to control the Linux kernel versions.&lt;/p&gt;
&lt;p&gt;Before starting with the specific vocabulary it is necessary to explain why you &lt;strong&gt;should&lt;/strong&gt; (many people would say &lt;em&gt;must&lt;/em&gt;) use VCS (git or other).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: When working on a project, files undergo multiple transformations, this is especially noticeable in graphic design and software development projects. As time goes by, it's normal to detect errors and then returning to a previous stage, what is often done to accomplish this is to create periodic backups, however, this approach is impractical in environments with constant changes and increasing number of files, this problem also grows substantially when working in large teams.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;: Each VCS proposes a different solution, in the case of Git, when talking about changes, it is meant to be a change at line level, ie. a file changes when one of its lines changes and if several changes are made on the same line, counts as a single change. Likewise, if several lines are changed in the same file, it is considered as many changes as lines were modified. Whenever we talk about changes, we will refer to this definition of change, at a line level. This makes Git extremely useful for text files with multiple lines (such as the source files of a programming language) and little applicable to files that don't follow this format (such as executable files, images, etc.).&lt;/p&gt;
&lt;h3 id="areas-in-git"&gt;&lt;a class="toclink" href="#areas-in-git"&gt;Areas in Git&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Git works mainly separating the changes into 3 areas:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Working Area: These are the files you are currently working with.&lt;/li&gt;
&lt;li&gt;Staging Area: These are the next changes that will be saved in the repository.&lt;/li&gt;
&lt;li&gt;Repository: These are the saved files, usually local and on the internet.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Also, to move from one area to another, there are different transitions. To pass from the Working Area to the Staging Area a &lt;strong&gt;&lt;code&gt;Stage&lt;/code&gt;&lt;/strong&gt; is made and to pass from the Staging Area to the repository a &lt;strong&gt;&lt;code&gt;Commit&lt;/code&gt;&lt;/strong&gt; is made.&lt;/p&gt;
&lt;h3 id="stage-vs-commit"&gt;&lt;a class="toclink" href="#stage-vs-commit"&gt;Stage vs Commit&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The typical process is as follows: the user works with their files in the Working Area, once he has finished the desired changes, he can select exactly which changes he wants to add to the repository, these changes are chosen and &lt;em&gt;"moved"&lt;/em&gt; to the Staging Area (the term move in this case is misleading because in the local system the files do not undergo any modification). Once all the changes have been moved to the Staging Area you can make a &lt;strong&gt;&lt;code&gt;commit&lt;/code&gt;&lt;/strong&gt;, the commit basically consists of &lt;em&gt;"packing everything that is in the Staging Area, associating a title and a description and uploading it to the repository"&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;At first this way of working could give the impression that the Staging Area does not fulfill any function, however it is especially relevant when one wants to make a commit with a subset of all the changes made, for example, if changes were made in the graphical interface and in the database but one wants each "package of changes" to be in a different commit, for that, first, the user would move to the Staging Area the changes related to the database, then they would make the commit and finally they would repeat the process with the changes related to graphical interface.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; The user is not required to commit all the changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt;: One could move to the Staging Area only a subset of the modified lines in a file, that's why it's important to remember that the term "change" refers to lines and not to files.&lt;/p&gt;
&lt;p&gt;Once the commit is made, the changes are definitively saved in the repository, the repository always exists at a local level on the user's machine and additionally, a copy is usually used remotely in some online provider, the most common are GitHub, Gitlab and Bitbucket.&lt;/p&gt;
&lt;h3 id="remote-repositories"&gt;&lt;a class="toclink" href="#remote-repositories"&gt;Remote Repositories&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When you work with a remote repository, three important terms arise: Pull, Push, Clone. As the names suggest, Pull brings the changes from the remote repository and applies them to the local repository, Push uploads the changes from the local repository to the remote repository and Clone, on the other hand, copies the remote repository and creates a local one, this operation is only done once (not to be confused with Fork).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Fork vs Clone:&lt;/strong&gt; A Fork is an independent copy of a repository. When one makes a Clone, one intends to work in their local computer and then upload the changes to the original repository, when one makes a Fork one intends to make a custom variant and become independent (to a certain extent) from the original repository. Making a Fork replaces the process of creating the repository and to do so one must go to the original repository.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; As long as the changes do not overlap (i.e. two users have not modified the same line), the same Git system takes care of combining them. When two or more users modify the same line of the same file, a "Conflict Resolution" is necessary. It is an advanced topic however it can be required daily in environments with multiple programmers, those who use git as the only users should not worry about this aspect.&lt;/p&gt;
&lt;h3 id="branches"&gt;&lt;a class="toclink" href="#branches"&gt;Branches&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The last important concept is the &lt;strong&gt;&lt;code&gt;branches&lt;/code&gt;&lt;/strong&gt;, this is the key concept of Git, within a repository one can have multiple branches, each branch allows to have an independent Working Area, this is done to keep the changes isolated, although the Stage-Commit process is the same as the one mentioned above, one may want to experiment with a new feature but without risking the rest of the codebase that already works correctly. In the case the experimentation is successful, it can be joined (merge) to the main branch. There are multiple criteria for the creation of branches, some organizations use a branch by features, others a branch by developers, etc. The way to use the branches is usually called "Git Strategy" or "Git Workflow", is considered good practice to have a simplified scheme with the following branches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Master: Where you have the code of the latest stable version&lt;/li&gt;
&lt;li&gt;Release: Where all the changes that will be in the next version are concentrated and the final tests are carried out.&lt;/li&gt;
&lt;li&gt;Develop: Where you have experimental code that is still being tested&lt;/li&gt;
&lt;li&gt;Hot Fix: Where errors detected a posteriori are repaired (outside the tests)&lt;/li&gt;
&lt;li&gt;Features: An independent branch for each feature you want to add to the software.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This can be visualized much better in an image. Each arrow indicates a &lt;em&gt;merge&lt;/em&gt; operation.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_0.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_0.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_0-thumbnail.png" width="658"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="additional-software"&gt;&lt;a class="toclink" href="#additional-software"&gt;Additional Software&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Git is a command line application (CLI), however, there are multiple softwares with a graphical interface built on top of this console application. In this case, we are going to talk about how to use one of the most popular: GitKraken.&lt;/p&gt;
&lt;p&gt;For the sake of simplicity, it is assumed that the user has correctly installed the Gitkraken software and that it is ready to use, therefore no initial installation and configuration steps are detailed.&lt;/p&gt;
&lt;h2 id="fork-of-a-repository"&gt;&lt;a class="toclink" href="#fork-of-a-repository"&gt;Fork of a repository&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned, a fork is a stand-alone copy of a repository. The repository already has its own creator and history of branches and commits but one makes a separated copy. This procedure can vary from one remote repository provider to another, here is the procedure for doing this in Github&lt;/p&gt;
&lt;h3 id="1-find-the-original-repository"&gt;&lt;a class="toclink" href="#1-find-the-original-repository"&gt;1. Find the original repository&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, we look in Github the repository from which the Fork is wanted, in this case, the Manim repository will be used, the animation engine created by 3Blue1Brown.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_1.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_1.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_1-thumbnail.png" width="1280"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As you can see in the image, the repository creator is 3b1b and the currently logged user is ELC so the owner and the creator are different users.&lt;/p&gt;
&lt;h3 id="2-perform-fork"&gt;&lt;a class="toclink" href="#2-perform-fork"&gt;2. Perform Fork&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To make a fork, simply click on the Fork button at the top.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_2.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_2.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_2-thumbnail.png" width="922"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Immediately afterward, GitHub will redirect us to a screen that tells us that the Fork is being created.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_3.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_3.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_3-thumbnail.png" width="1268"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once the process is finished, a repository of the same name will be created in the logged user account.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_4.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_4.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_4-thumbnail.png" width="924"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As you can see in the image above, the repository now belongs to &lt;strong&gt;&lt;code&gt;ELC&lt;/code&gt;&lt;/strong&gt;, with a small label below that indicates that the repository is a Fork. A sign that this repository is independent and belongs to the logged user is that there is a new section &lt;strong&gt;"Settings"&lt;/strong&gt; that otherwise would not appear.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; This section may appear if you are a contributor to the repository, however that feature may vary from provider to provider and will not be detailed in this guide.&lt;/p&gt;
&lt;p&gt;One last confirmation could be the Forks count which is a common number for all Forks.&lt;/p&gt;
&lt;p&gt;From now on the evolution of this new repository can be completely independent of the original.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT:&lt;/strong&gt;What is the difference between making a fork and creating an identical repository with the same files? When doing a Fork you have a common commit history with the original repository, so it is possible to combine new changes from the original to any of the Forks (merge) and from the Forks back to the original (Pull Request).&lt;/p&gt;
&lt;p&gt;The alternative procedure of creating a repository from scratch as well as cloning from GitKraken is detailed in the following section&lt;/p&gt;
&lt;h2 id="clone-a-repository"&gt;&lt;a class="toclink" href="#clone-a-repository"&gt;Clone a repository&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The most traditional approach is to first create the repository on the remote server (Github or similar) and then clone it. In this case, we are going to create a repository called "gitkraken-tutorial" in Github.&lt;/p&gt;
&lt;h3 id="1-create-a-repository"&gt;&lt;a class="toclink" href="#1-create-a-repository"&gt;1. Create a repository&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This can be done from the Github homepage.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_5.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_5.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_5-thumbnail.png" width="1279"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="1-alternative-create-a-repository"&gt;&lt;a class="toclink" href="#1-alternative-create-a-repository"&gt;1 (Alternative). Create a repository&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Or from the repository section.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_6.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_6.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_6-thumbnail.png" width="1279"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="2-complete-the-necessary-information"&gt;&lt;a class="toclink" href="#2-complete-the-necessary-information"&gt;2. Complete the necessary information&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT:&lt;/strong&gt; In order to clone, our repository must be "Initialized" therefore, it is essential to check the option &lt;em&gt;"Initialize this repository with a README"&lt;/em&gt;. The gitignore options allow git to ignore certain files (temporary files, caches, etc.) and the license allows you to choose a standard license from a list.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_7.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_7.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_7-thumbnail.png" width="678"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="3-get-repository-url"&gt;&lt;a class="toclink" href="#3-get-repository-url"&gt;3. Get Repository URL&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Two perspectives can be used to clone the repository from GitKraken:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Linking GitHub's account with Gitkraken's account&lt;/li&gt;
&lt;li&gt;Use the repository URL&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All git repository services attach a public URL to the repository, so this approach will be taken because it is common to all providers.&lt;/p&gt;
&lt;p&gt;Once you follow the steps in the images, the URL will be copied to the clipboard.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_8.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_8.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_8-thumbnail.png" width="1277"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_9.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_9.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_9-thumbnail.png" width="1277"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="4-open-the-window-of-clone-inside-the-gitkraken"&gt;&lt;a class="toclink" href="#4-open-the-window-of-clone-inside-the-gitkraken"&gt;4. Open the window of Clone inside the GitKraken&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the File menu, select the option "Clone Repo".&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_10.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_10.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_10-thumbnail.png" width="370"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="4-alternative-1-open-the-clone-window-inside-the-gitkraken"&gt;&lt;a class="toclink" href="#4-alternative-1-open-the-clone-window-inside-the-gitkraken"&gt;4 (Alternative 1). Open the Clone window inside the GitKraken&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;At any time, you can use the button located in the upper left corner.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_11.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_11.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_11-thumbnail.png" width="1302"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Then choose the Clone option.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_12.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_12.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_12-thumbnail.png" width="164"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="4-alternative-2-open-the-clone-window-inside-the-gitkraken"&gt;&lt;a class="toclink" href="#4-alternative-2-open-the-clone-window-inside-the-gitkraken"&gt;4 (Alternative 2). Open the Clone window inside the GitKraken&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If no repository is open, the menu can be accessed directly from the home screen.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_13.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_13.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_13-thumbnail.png" width="1302"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="5-paste-the-url"&gt;&lt;a class="toclink" href="#5-paste-the-url"&gt;5. Paste the URL&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Additionally, you can detail the &lt;strong&gt;&lt;code&gt;path&lt;/code&gt;&lt;/strong&gt; where the repository will be cloned and change the name of the destination folder. It is recommended to have a &lt;em&gt;"Repositories"&lt;/em&gt; folder and clone all repositories there.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_14.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_14.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_14-thumbnail.png" width="796"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="5-notification-of-success"&gt;&lt;a class="toclink" href="#5-notification-of-success"&gt;5. Notification of Success&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once the repository has been cloned, a notification should appear at the top saying that the operation was successful. One can use the "Open Now" button to open the repository immediately. In this case, it will not be done to illustrate how to open a repository from scratch.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_15.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_15.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_15-thumbnail.png" width="1302"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="open-a-repository"&gt;&lt;a class="toclink" href="#open-a-repository"&gt;Open a repository&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once the repository has been cloned, it is necessary to open it in order to start working.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; The repository could have been initialized instead of cloned but this scenario is unlikely as a link to the remote repository should then be made. As the approach outlined at the beginning is generally used, initialization of repositories is beyond the scope of this guide.&lt;/p&gt;
&lt;h3 id="1-open-window"&gt;&lt;a class="toclink" href="#1-open-window"&gt;1. Open Window&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the File menu, select the option "Open Repo".&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_16.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_16.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_16-thumbnail.png" width="368"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="1-alternative-1-open-window"&gt;&lt;a class="toclink" href="#1-alternative-1-open-window"&gt;1 (Alternative 1). Open Window&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In addition, the icon in the upper left corner can be used.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_17.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_17.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_17-thumbnail.png" width="1302"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="1-alternative-2-open-window"&gt;&lt;a class="toclink" href="#1-alternative-2-open-window"&gt;1 (Alternative 2). Open Window&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If no repository is opened, you can use the start screen button.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_18.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_18.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_18-thumbnail.png" width="1302"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="2-select-the-repository"&gt;&lt;a class="toclink" href="#2-select-the-repository"&gt;2. Select the repository&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;"Open a Repository" is selected.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_19.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_19.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_19-thumbnail.png" width="360"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="3-select-the-folder"&gt;&lt;a class="toclink" href="#3-select-the-folder"&gt;3. Select the folder&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Navigate to the folder where the repository is located, an easy way to identify it is that you should see a folder called ".git" (This folder may not appear if you do not have Windows hidden files enabled).&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_20.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_20.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_20-thumbnail.png" width="875"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="interface-elements"&gt;&lt;a class="toclink" href="#interface-elements"&gt;Interface Elements&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="basic-interface"&gt;&lt;a class="toclink" href="#basic-interface"&gt;Basic interface&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When opening a repository we will find the basic interface.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_21-en.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_21-en.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_21-en-thumbnail.png" width="1300"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="commits-and-branches-tree"&gt;&lt;a class="toclink" href="#commits-and-branches-tree"&gt;Commits and Branches Tree&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When having several commits and branches, in the central part, it is possible to see the bifurcations and the unions, in the following image is shown a project with several branches (Only as an example).&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_22.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_22.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_22-thumbnail.png" width="807"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="add-changes"&gt;&lt;a class="toclink" href="#add-changes"&gt;Add Changes&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Git tools can be separated into two categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Integrated with IDEs&lt;/li&gt;
&lt;li&gt;Decoupled&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Many IDEs come with their own integration with Git, some examples of this are Eclipse, Visual Studio and PyCharm. However, it is possible to use completely decoupled applications such as Gitkraken, Github Desktop or the git CLI itself.&lt;/p&gt;
&lt;p&gt;The former have the advantage that the user does not have to leave the application in which he develops the code and tests, but has the disadvantage that he can easily confuse which is his current branch and if the system is in a consistent state, in addition, each IDE will have its special interface, and the IDE tend to change if the programming language is changed. On the other hand, decoupled tools such as Gitkraken allow the developer to use the IDE only for what was designed, programming, debugging and testing, abstracting completely from the version control system, this approach has the advantage that the user only has to worry about version control when starting to work and when making the Stage-Commit and that the same interface is used regardless of which IDE has been used, but brings as a disadvantage that you must have additional software installed.&lt;/p&gt;
&lt;p&gt;When using Gitkraken it is possible to work as usual in the traditional IDE and when you want to add changes to the repository what will appear is something like the following:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_23.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_23.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_23-thumbnail.png" width="343"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The acronym WIP (Work in Progress) refers to the Working Area. By clicking on this box you can see on the right side the changes made separated by files and also a clear division between the Working Area and the Staging Area.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_24-en.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_24-en.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_24-en-thumbnail.png" width="322"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It is also important to clarify the function of three buttons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trash basket in the upper right corner: &lt;strong&gt;DELETEs&lt;/strong&gt; all changes to the Working Area, use only if you know what you are doing.&lt;/li&gt;
&lt;li&gt;Tree: Allows to visualize the files in the form of a tree of directories, depending on the configuration may not be selected by default, it is recommended to use it.&lt;/li&gt;
&lt;li&gt;Stage Files/changes to commit: Generates a commit with the given title and description of all changes that are in the Staging Area.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_25.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_25.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_25.png" width="329"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_26.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_26.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_26.png" width="336"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you click on any of the files in both the Working and Staging Area, you can see a detail of the changes:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_27.png"&gt;&lt;img alt="image alt text" class="b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_27.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_27-thumbnail.png" width="1261"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Each line shaded with red implies that that line was in the last version and will be removed, the green shaded indicate that they were not in the last version and will be added. In Git there is no concept of modifying a line so if a modification is made, the line from the previous version will be deleted and an identical one will be added but with the changes made.&lt;/p&gt;
&lt;p&gt;If one hovers the cursor over one of these lines, a button with a plus sign (+) will appear that will allow us to move individual lines to the Staging Area:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_28.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_28.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_28-thumbnail.png" width="80"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Gitkraken, in turn, identifies changes by sections in files and allows several sections to be added to the Staging Area.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_29.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_29.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_29-thumbnail.png" width="173"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Finally, if you want to add all the changes of a file to the Staging Area, you can position the cursor over that file and use the "Stage File" button that will appear. It is also possible to move ALL files from the Working Area to the Staging Area with the &lt;em&gt;"Stage all Changes"&lt;/em&gt; button:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_30.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_30.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_30-thumbnail.png" width="414"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The process to remove changes from the Staging Area and pass them to the Working Area is identical, only the corresponding file must be selected first from the Staging Area, in this case the buttons are red and the button with the plus (+) becomes a minus (-):&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_31.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_31.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_31-thumbnail.png" width="74"&gt;&lt;/a&gt;
&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_32.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_32.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_32-thumbnail.png" width="131"&gt;&lt;/a&gt;
&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_33.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_33.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_33-thumbnail.png" width="424"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once you have moved the desired changes to the Staging Area, you can create the desired commit, you need to assign it a title, you can also detail an optional description:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_34.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_34.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_34-thumbnail.png" width="328"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once the commit is done, it will appear in the main screen with the name assigned to it:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_35.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_35.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_35-thumbnail.png" width="346"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It is important to note that this generates the commit in the &lt;strong&gt;LOCAL&lt;/strong&gt; repository and that these changes have not yet impacted the remote repository, Gitkraken shows us this by using a computer for the Local repository and the Github user logo to represent the remote repository. In the next section, we will see how to synchronize both repositories.&lt;/p&gt;
&lt;h2 id="synchronization-with-remote-repositories"&gt;&lt;a class="toclink" href="#synchronization-with-remote-repositories"&gt;Synchronization with remote repositories&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As mentioned before, to keep two repositories up to date you need to use the Pull and Push actions&lt;/p&gt;
&lt;h3 id="download-changes-from-the-remote-repository"&gt;&lt;a class="toclink" href="#download-changes-from-the-remote-repository"&gt;Download changes from the remote repository&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is considered a good practice to always pull before uploading changes, this will bring any changes that we could not have in our local machine. In this opportunity, we will have to distinguish between the Pull action and the Fetch action.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fetch:&lt;/strong&gt; Check if there are changes in the remote repository and shows us what is the status of the remote with respect to the local&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pull:&lt;/strong&gt; Makes a Fetch and applies those changes to the local repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Fetch is, therefore, a completely safe action, while Pull can bring changes that generate collisions with ours, although this is not frequent and is only possible in environments with multiple users, it is considered a good practice that the user resolves conflicts on his local computer and then can upload the changes. Otherwise, the remote repository could be left in an inconsistent state, halting the progress of other team members.&lt;/p&gt;
&lt;p&gt;In the Gitkraken action bar we have the Fetch action:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_36.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_36.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_36-thumbnail.png" width="398"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To access the Pull action, choose the arrow next to Fetch:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_37.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_37.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_37-thumbnail.png" width="398"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_38.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_38.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_38-thumbnail.png" width="376"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the case of the example repository, the Pull should be successful as there were no changes in the remote repository.&lt;/p&gt;
&lt;h3 id="upload-changes-to-the-remote-repository"&gt;&lt;a class="toclink" href="#upload-changes-to-the-remote-repository"&gt;Upload changes to the remote repository&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To upload changes it is necessary to first perform a Pull to resolve conflicts (if any) once resolved, you can perform a Push using the associated button in the action bar:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_39.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_39.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_39-thumbnail.png" width="393"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once done, the easiest way to verify that it was successful is to see the commits tree.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_40.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_40.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_40-thumbnail.png" width="350"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This time both the Github user logo and the computer are together, showing that the content is synchronized.&lt;/p&gt;
&lt;h3 id="example-of-fetch-and-pull"&gt;&lt;a class="toclink" href="#example-of-fetch-and-pull"&gt;Example of Fetch and Pull&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To illustrate what a reverse situation would look like (changes were made to the remote repository and we want to download them). First, we do Fetch and we'll see something like this:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_41.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_41.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_41-thumbnail.png" width="362"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As you can see, the branch master is "advanced" and has a commit called &lt;em&gt;"Update README.md"&lt;/em&gt; that is only in the remote repository (evidenced by the Github account logo). And our local version is "behind". In this situation we have to evaluate the changes and if there are any conflicts (including the Working Area files).  It is recommended not to have anything in the Working Area at the time of Pulling, that is, that all changes are already inside commits, this simplifies the process and decreases the probability of finding conflicts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; There are advanced situations where you can temporarily save Working Area changes in a Stash but this feature is outside the scope of this guide.&lt;/p&gt;
&lt;p&gt;In case there are no conflicts, a Pull can be performed without problems:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_42.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_42.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_42-thumbnail.png" width="340"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The result is as expected, both the local and remote repositories are synchronized.&lt;/p&gt;
&lt;h2 id="working-in-multiple-branches"&gt;&lt;a class="toclink" href="#working-in-multiple-branches"&gt;Working in multiple branches&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once you can work efficiently on one branch, it is highly recommended to select one Git Strategy and use multiple branches.&lt;/p&gt;
&lt;h3 id="create-branch"&gt;&lt;a class="toclink" href="#create-branch"&gt;Create Branch&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To create a branch we must first position ourselves in a base branch, this is the branch from which the new branch will bifurcate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; There is the concept of orphan branches, which are branches that are not derived from any other branch. However, their use is usually very particular and specific and they are therefore beyond the scope of this guide.&lt;/p&gt;
&lt;p&gt;In this case, we will create a master branch, add two commits, join it and then delete it.&lt;/p&gt;
&lt;p&gt;In the first place, we position ourselves in master, double-clicking in &lt;em&gt;"master"&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_43.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_43.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_43-thumbnail.png" width="391"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Then use the &lt;strong&gt;&lt;code&gt;Branch&lt;/code&gt;&lt;/strong&gt; button on the action bar.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_44.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_44.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_44-thumbnail.png" width="381"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Then write the name of the branch and press enter:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_45.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_45.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_45-thumbnail.png" width="356"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Gitkraken allows us to see in several places that the branch was successfully created.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_46.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_46.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_46-thumbnail.png" width="503"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;However, it is possible to observe that in the commits tree that the master branch does not appear, this is because it is hidden in the &lt;em&gt;+1 icon&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_47.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_47.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_47-thumbnail.png" width="503"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When passing the cursor over it we can see that the branch is visible again:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_48.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_48.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_48-thumbnail.png" width="330"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This simplification of the interface is due to the fact that the content of both branches is identical (we haven't made any changes yet) and although it can be a little confusing for beginners, it is extremely useful when you have multiple branches. On the other hand, GitKraken's visual aid allows us to observe that the "add-license" branch only exists in the local context and does not yet exist in the remote repository.&lt;/p&gt;
&lt;h3 id="join-branches-merge"&gt;&lt;a class="toclink" href="#join-branches-merge"&gt;Join Branches (Merge)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In order to join two branches it is necessary that they are different, for it some commits are added to the branch "add-license". After adding the commits, you get something like the following:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_49.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_49.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_49-thumbnail.png" width="327"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;While the branch still exists only in the local context, it is important to see how it is "ahead" of the master branch. Although in the scheme presented at the beginning the branches are arranged parallel to each other, Gitkraken only arranges them that way when there are several changes, that is, only when the master branch has been modified and that this modification is not one of the commits of the branch with which it is aligned (add-license) in this case. To illustrate this example, a change will be added to the master branch directly (not in the add-license branch).&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_50.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_50.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_50-thumbnail.png" width="331"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This way of visualizing branches is more similar to the previous view, the view changed because the commit "Add Contribution Guide" was added directly in the master.&lt;/p&gt;
&lt;p&gt;Before joining the branches we are going to make a Push, in this case, as the branch does not exist in the remote repository, it will ask us if we want to link it with some branch of the already existing remote repository, if we leave the space blank and click on &lt;strong&gt;&lt;code&gt;Submit&lt;/code&gt;&lt;/strong&gt;, it will create a branch with the same name in the remote repository.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_51.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_51.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_51-thumbnail.png" width="777"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now both branches are synchronized with the remote repository:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_52.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_52.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_52-thumbnail.png" width="333"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;While it was not necessary to make a Push of the branch before joining it, it is considered good practice to make the history of changes public so other users can see who made the changes and how.&lt;/p&gt;
&lt;p&gt;To merge branches one must click on the name of the source branch and drag and drop on the name of the destination branch, this will display the following menu, where we select the Merge option.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_53.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_53.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_53-thumbnail.png" width="356"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_54.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_54.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_54-thumbnail.png" width="446"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once the option is chosen, the commits and branches tree will look similar to the next one:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_55.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_55.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_55-thumbnail.png" width="332"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As you can see the merge was successful, however, it will not yet be reflected in the remote repository, therefore, it is necessary to activate the master repository (by double-clicking on the name) and then do a Push.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_56.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_56.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_56-thumbnail.png" width="329"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once the Push is done, both the branches and the Merge operation are synchronized in the remote and local repository.&lt;/p&gt;
&lt;h3 id="erase-branch"&gt;&lt;a class="toclink" href="#erase-branch"&gt;Erase Branch&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Throughout the life of a development project can be created infinity of branches, therefore, to keep the interface clean, it is a good practice to remove the branches after they joined (merge) to master (or to the branch that corresponds according to the Git Workflow established).&lt;/p&gt;
&lt;p&gt;To remove a branch just right click on the name and select the option that removes it from both the local and remote repositories.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_57.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_57.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_57-thumbnail.png" width="460"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;GitKraken will warn us that this is a destructive operation and can not be undone, select &lt;strong&gt;Delete&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_58.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_58.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_58-thumbnail.png" width="717"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once the branch has been successfully removed the commits and branches tree will look similar to the next one:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_59.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_59.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_59-thumbnail.png" width="331"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As you can see, the deleted branch is neither in the local nor in the remote repository, however, and this is where the utility is, it can be clearly seen as it once existed and consisted of two commits that were then attached to the master. The advantage of this functionality is that one can remove the branches and not lose the history of what was done, having a separation in the commits that allows you to easily track who made what changes and how they were made. This wouldn't be possible (or rather, it would be much more complex) if you only worked with the master branch.&lt;/p&gt;
&lt;h2 id="pull-requests"&gt;&lt;a class="toclink" href="#pull-requests"&gt;Pull Requests&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In a development environment, it is rare for developers to perform merge to master directly, which is why an approval and review mechanism is used before merge can be performed on critical branches. Each provider calls that process differently, in the most popular (Github) that process is called Pull Request.&lt;/p&gt;
&lt;p&gt;A Pull Request is basically the following: I have changes made and would like to attach them to this branch. It is a common practice in the most critical branches within development projects, where the person in charge of those reviews and approvals is usually called &lt;em&gt;Release Manager&lt;/em&gt; and is also extremely popular in Open Source projects, where you have the main repository and people who want to contribute, not having permissions to edit the repository directly, can make Pull Requests. The creator of the repository will then be able to accept or reject them.&lt;/p&gt;
&lt;p&gt;Although Pull Requests are usually done through the provider's interface (Github in this case). They can also be done from GitKraken.&lt;/p&gt;
&lt;p&gt;The procedure is shown for illustrative purposes only:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Right click on the branch from which you want to make the Pull Request&lt;/li&gt;
&lt;li&gt;The Pull Request option is selected&lt;/li&gt;
&lt;li&gt;The requested fields are completed&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_60.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_60.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_60-thumbnail.png" width="397"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/git-guide-with-visual-interface/image_61.png"&gt;&lt;img alt="image alt text" class="narrow b-lazy" data-src="/blog/images/git-guide-with-visual-interface/image_61.png" src="https://elc.github.io/blog/images/git-guide-with-visual-interface/image_61-thumbnail.png" width="479"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; Pull Requests must generally be made in a specific way that is detailed in the same repository of the software to which one wants to contribute to the example shown is trivial, only to have a notion of how the procedure would be.&lt;/p&gt;
&lt;h2 id="additional-features"&gt;&lt;a class="toclink" href="#additional-features"&gt;Additional Features&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Apart from everything mentioned in this guide, there is still a lot of ground to explore both in what Git allows and what can be done with GitKraken, some of these possibilities are listed below for the reader to investigate in more detail if desired&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Have repositories within repositories. Search: &lt;strong&gt;Submodules&lt;/strong&gt; and &lt;strong&gt;Subtree&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Apply only one commit from one branch to another and not make a history union. Search: &lt;strong&gt;Cherry Pick Commit&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Have branches completely independent of others: Search: &lt;strong&gt;Orphan Branch&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Unify branches forgetting history. Search: &lt;strong&gt;Rebase&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Add content to a previous commit. Search: &lt;strong&gt;Amend&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Undo several commits while keeping the changes. Search: &lt;strong&gt;Soft Reset&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Force changes in the remote repository. Search: &lt;strong&gt;Push Force&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Revert changes of a specific commit. Search: &lt;strong&gt;Revert&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Save changes to the Working Area in a temporary space. Search: &lt;strong&gt;Stash&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Create tags to identify specific versions of the entire repository when it is in a consistent state (baseline). Search: &lt;strong&gt;Tags&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of the above features can only be done from the console, i.e. they are not fully supported in GitKraken.&lt;/p&gt;
&lt;h2 id="aditional-resources"&gt;&lt;a class="toclink" href="#aditional-resources"&gt;Aditional Resources&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gitkraken.com/" target="_blank"&gt;GitKraken Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/" target="_blank"&gt;Git Official Website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learngitbranching.js.org/" target="_blank"&gt;Git Console Sandbox&lt;/a&gt;: It allows to experiment with several git console commands in a sandbox environment inside the browser.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dictcp/awesome-git" target="_blank"&gt;Awesome Git&lt;/a&gt;: A curated list of amazingly awesome Git tools, resources and shiny things.&lt;/li&gt;
&lt;/ul&gt;</content><category term="Software Engineer"></category><category term="Git"></category><category term="GUI"></category><category term="GitKraken"></category></entry><entry><title>Multi-Floor Elevator Simulation with AnyLogic</title><link href="https://elc.github.io/posts/multi-floor-elevator-simulation-anylogic" rel="alternate"></link><published>2019-04-06T00:00:00-03:00</published><updated>2019-04-06T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2019-04-06:/posts/multi-floor-elevator-simulation-anylogic</id><summary type="html">&lt;!-- Status: draft --&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/elevator-simulation-headerimage.png"&gt;&lt;img alt="Elevator Header Image" class="b-lazy" data-src="/blog/images/elevator-simulation/elevator-simulation-headerimage.png" src="https://elc.github.io/blog/images/elevator-simulation/elevator-simulation-headerimage-thumbnail.png" width="1920"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;In my 4th year of University I had what would become one of my favorite courses, Simulation, where, as a final project, each student (or team of students) should choose a real problematic situation and create a simulation model (with AnyLogic). I choose something I was familiar with, the never-ending …&lt;/p&gt;</summary><content type="html">&lt;!-- Status: draft --&gt;

&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/elevator-simulation-headerimage.png"&gt;&lt;img alt="Elevator Header Image" class="b-lazy" data-src="/blog/images/elevator-simulation/elevator-simulation-headerimage.png" src="https://elc.github.io/blog/images/elevator-simulation/elevator-simulation-headerimage-thumbnail.png" width="1920"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;In my 4th year of University I had what would become one of my favorite courses, Simulation, where, as a final project, each student (or team of students) should choose a real problematic situation and create a simulation model (with AnyLogic). I choose something I was familiar with, the never-ending queue of the elevators of the University building, I asked for the blueprints and simulate several alternatives to find which was the best.&lt;/p&gt;


&lt;p&gt;In case you never heard of what simulation is, don't worry, I will give you a quick introduction to this incredible world. For those who are already familiar with it, you can &lt;a href="#context"&gt;skip the introduction section&lt;/a&gt; or if you prefer, jump directly to the &lt;a href="#model"&gt;computational model&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="introduction"&gt;&lt;a class="toclink" href="#introduction"&gt;Introduction&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Simulation is a way of problem-solving, it basically consists of translating a problem into a digital realm, make changes or test alternatives in this new environment and see the results. This information is later used for decision making. Saving loads of money, time and manpower.&lt;/p&gt;
&lt;h3 id="why-is-this-necessary-or-useful"&gt;&lt;a class="toclink" href="#why-is-this-necessary-or-useful"&gt;Why is this necessary or useful?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Many processes can't be stopped or delayed, industries, for example, can just stop producing in order to test alternatives that might result in terrible outcomes! For this reason, it is safer, cheaper and much more convenient to use simulation.&lt;/p&gt;
&lt;h3 id="what-are-the-advantages"&gt;&lt;a class="toclink" href="#what-are-the-advantages"&gt;What are the advantages?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Simulation Software Companies usually compare simulation with working with spreadsheets (such as Excel) in order to make decision and, although spreadsheets are really useful for some problems, when it comes to testing alternatives of the real world, a dynamic, interactive and more visual approach is preferred, especially when talking to non-technical people, who probably will be the ones making the final decision.&lt;/p&gt;
&lt;p&gt;Another point is that Simulation Software relies (in most cases) on random number generators and thus the outcome of this software tends to be much similar to the real world. As opposed to the general analytical and "ideal" approach one takes when using spreadsheets.&lt;/p&gt;
&lt;h3 id="how-can-be-done"&gt;&lt;a class="toclink" href="#how-can-be-done"&gt;How can be done?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Simulation software exists, both commercial and open-source and when a graphic user interface (GUI) is not needed, even some programming languages may be used with some additional libraries. In this article, I'll be talking about AnyLogic, a commercial software which has a free student license.&lt;/p&gt;
&lt;h2 id="context"&gt;&lt;a class="toclink" href="#context"&gt;Context&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I study at the "Universidad Tecnológica Nacional (UTN)" also translated as (National Technological University), it has several buildings but the biggest is the main one. There are 5 different departments, Mechanical Engineering, Chemistry Engineering, Electric Engineering, Civil Engineering, and Information Systems Engineering, each department has its own floor. The building has 5 floors and one underground level. The building is old, preserving the really high ceilings and the long stairs common in the time of construction, making the elevators a must. There are two elevators but only one goes to the fourth and fifth floor.&lt;/p&gt;
&lt;p&gt;To better represent the distribution, the blueprints were used (with permission):&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="./blog/images/elevator-simulation/floor-distribution.png"&gt;&lt;img alt="Elevator Header Image" class="b-lazy" data-src="/blog/images/elevator-simulation/floor-distribution.png" src="https://elc.github.io/blog/images/elevator-simulation/floor-distribution-thumbnail.png" width="1202"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="problem"&gt;&lt;a class="toclink" href="#problem"&gt;Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The university has approximately 1000 students (first year aside), and for two elevators in the rush hour, it is natural to think that long queues will form. In my fourth year, I had the chance to experiment and try to fix this situation, most people believe that the long queues are due to the internal logic of the elevator so I thought, what if we change that? As a result, with another two classmates, we decided to test several alternatives.&lt;/p&gt;
&lt;p&gt;But before trying new alternatives, we had to identify how to the elevator is working now.&lt;/p&gt;
&lt;p&gt;Right now, when the elevator is moving up, it stops in the floors requested from inside, when is moving down, it stops in the floors requested from both inside and outside (This is called Actual in our model).&lt;/p&gt;
&lt;p&gt;This information was obtained via experimentation since there was no manual available to get the information from.&lt;/p&gt;
&lt;h2 id="alternatives"&gt;&lt;a class="toclink" href="#alternatives"&gt;Alternatives&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The alternatives we first thought was FIFO (First in, First Out), we knew it would be awful but it's a good way to determine what the worst non-cyclic is like (Cycles are really bad since it could produce infinite loops). So in order to test how good the other alternatives are we chose FIFO to represent the worst possible solution. The other alternatives are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Alternative 1 (ALT 1):&lt;/strong&gt; The same as Actual but, when is lazy, it goes to Ground Floor.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alternative 2 (ALT 2):&lt;/strong&gt; The elevator stops in the floors requested from both inside and outside when moving either up or down&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alternative 3 (ALT 3):&lt;/strong&gt; The same as ALT 2 but, when is lazy, it goes to Ground Floor.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="simplifications"&gt;&lt;a class="toclink" href="#simplifications"&gt;Simplifications&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before diving into the model itself, some simplifications must be stated:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The population of interest is the students, so teachers and administration staff are not taken into account&lt;/li&gt;
&lt;li&gt;When a student goes to the ground floor, we assume they leave the university, since there is nothing they can do there. All the offices on the ground floor are for the University staff.&lt;/li&gt;
&lt;li&gt;The simulation only involves one of the two elevators, to get a simpler model&lt;/li&gt;
&lt;li&gt;The simulation doesn't cover the underground floor for two reasons: 1. The chosen elevator can't go there and 2. The number of people going to that floor is very low.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="students-behavior"&gt;&lt;a class="toclink" href="#students-behavior"&gt;Students behavior&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each student has a particular behavior and it is important to model it correctly, the following are a simplified and a detailed version of this behavior.&lt;/p&gt;
&lt;h3 id="simplified"&gt;&lt;a class="toclink" href="#simplified"&gt;Simplified&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The student goes into the university, enters a specific classroom and stays there for a certain amount of time and then leaves.&lt;/p&gt;
&lt;h3 id="detailed"&gt;&lt;a class="toclink" href="#detailed"&gt;Detailed&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The actual behavior is a bit more complex:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Every student enters the building in the Ground Floor (GF)&lt;/li&gt;
&lt;li&gt;The students go from the GF to another floor and vice versa. It is rarely that a student travels from a floor different from GF to another floor since all the activities usually are covered in one or more classrooms on the same floor. This behavior exists but it is considered as not significant.&lt;/li&gt;
&lt;li&gt;Students tend to tolerate longer waits when going to the GF and when going from the GF their tolerance is much lower.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of the previous allow us to introduce a more specific problem: The GF queue. The main objective of the simulation will be reducing as much as possible both the length of the queue and the waiting time of the GF since this is the scenario where there is the lowest tolerance.&lt;/p&gt;
&lt;p&gt;It is also necessary to mention that since the tolerance is too low, an auxiliary system should be modeled too since many of the users will "abandon" the queue and use the stairs instead.&lt;/p&gt;
&lt;p&gt;The behavior of the students is represented in the following diagram:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/student-behavior.jpg"&gt;&lt;img alt="Student Behavior" class="b-lazy" data-src="/blog/images/elevator-simulation/student-behavior.jpg" src="https://elc.github.io/blog/images/elevator-simulation/student-behavior-thumbnail.jpg" width="1752"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="model"&gt;&lt;a class="toclink" href="#model"&gt;Model&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are different types of simulation but for this particular situation, we choose "Agent-Based", since it is natural to think the elevators and the students as two agents interacting with each other.&lt;/p&gt;
&lt;p&gt;When talking about Agents and how they interact, a tool called "State Machines" is used. This artifact models the possible "states" of a particular agent and "transitions" which are how the agent goes from one state to the other&lt;/p&gt;
&lt;p&gt;State Machines are defined in the UML standard but in this case, a modified version will be used, this version is the one that AnyLogic uses. And in the software, there are 3 types of transitions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By Delay: The transition occurs automatically after a certain delay.&lt;/li&gt;
&lt;li&gt;By Condition: The transition occurs whenever a certain condition is true.&lt;/li&gt;
&lt;li&gt;By Message: The transition occurs when the agent receives a specific message from an agent.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="global-conditions"&gt;&lt;a class="toclink" href="#global-conditions"&gt;Global Conditions&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In addition to the two main agents, there are global variables that affect the whole simulation such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Storey Height: It includes the height from the floor to the ceiling and the thickness of the ceiling.&lt;/li&gt;
&lt;li&gt;Average Students per minute: the arrival frequency of the students to the system.&lt;/li&gt;
&lt;li&gt;Average Mass of students (Kg): The average mass of the students, as a first approximation a triangular distribution is used to estimate the weights.&lt;/li&gt;
&lt;li&gt;Average time to enter into the elevator (s): it is the time each person takes to enter the elevator, it is a small amount but it can accumulate when there are lots of people in the queue.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="elevator-agent"&gt;&lt;a class="toclink" href="#elevator-agent"&gt;Elevator Agent&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On the other hand, the elevator also has its own variables, these variables can be changed any time during the simulation but when doing an experiment, they should be set once at the beginning and kept fixed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Capacity (Kg): Maximum capacity for the elevator, it is approximately 5 people (75Kg each) as default.&lt;/li&gt;
&lt;li&gt;Speed (m/s): Speed at which the elevator moves&lt;/li&gt;
&lt;li&gt;Service Policy: Determines how the Requests should be served. This is the main variable since it is where the alternatives should take effect.&lt;/li&gt;
&lt;li&gt;Number of users inside: The number of people inside&lt;/li&gt;
&lt;li&gt;Requests list: Collection of requests in the order they were received, used by the service policy to determine which is the next.&lt;/li&gt;
&lt;li&gt;Actual Floor: Floor the elevator is in at the moment.&lt;/li&gt;
&lt;li&gt;Destination Floor: Floor of the currently served Request.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The state machine of this agent is the following:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/elevator-state-machine.jpg"&gt;&lt;img alt="Elevator State Machine" class="b-lazy" data-src="/blog/images/elevator-simulation/elevator-state-machine.jpg" src="https://elc.github.io/blog/images/elevator-simulation/elevator-state-machine-thumbnail.jpg" width="1374"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Where there are two main states:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Waiting: The elevator is stopped at a certain floor, it could be loading/unloading people, empty or full.&lt;/li&gt;
&lt;li&gt;Operating: The Elevator starts moving until reaching the destination floor, there is a delay to open and close the doors.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="student-agent"&gt;&lt;a class="toclink" href="#student-agent"&gt;Student Agent&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The student agent is a bit different since there are loads of student so it has more random particularities.&lt;/p&gt;
&lt;p&gt;The variables of this agent are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Time to enter the elevator (s): Each person takes a different amount of time to enter the elevator.&lt;/li&gt;
&lt;li&gt;Mass (Kg): body mass of the student, determined using a triangular distribution&lt;/li&gt;
&lt;li&gt;Probability of using the stairs: Each user as a particular desire to use the stairs, whether it being because the queue is too long, they have already waited for too much or personal preference. This probability is inversely proportional to the number of the floor the student should go.&lt;/li&gt;
&lt;li&gt;Speed (m/s): Each student has a particular speed, which affects their speed while using the stairs, the speed of going upstairs and downstairs are different but both proportional to the average speed of the person.&lt;/li&gt;
&lt;li&gt;Tolerance to the waits (s): Maximum amount of time the student is willing to wait in the queue, if it is exceeded, they will abandon the queue and use the stairs.&lt;/li&gt;
&lt;li&gt;Actual Floor: Floor the student is at the moment.&lt;/li&gt;
&lt;li&gt;Destination Floor: Floor the student is willing to go.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The state machine of the students is the following:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/pedestrian-state-machine.jpg"&gt;&lt;img alt="Student State Machine" class="b-lazy" data-src="/blog/images/elevator-simulation/pedestrian-state-machine.jpg" src="https://elc.github.io/blog/images/elevator-simulation/pedestrian-state-machine-thumbnail.jpg" width="1346"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Each student has 3 possible states:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Walking: When the user is neither inside the elevator or waiting in a queue&lt;/li&gt;
&lt;li&gt;InQueue: When the user is waiting in a queue&lt;/li&gt;
&lt;li&gt;WaitingInside: When the user is inside the elevator&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="the-experiment"&gt;&lt;a class="toclink" href="#the-experiment"&gt;The Experiment&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once everything is set up in the software, a set of experiments are run and then statistical methods are used to determine which alternative is the best (with a certain level of confidence). This post was more of the "theory" behind the model but to really understand how it works I recommend you to play with the demo available in the next section.&lt;/p&gt;
&lt;p&gt;Among the five alternatives, it was necessary to identify which were the worsts, so both the average length and the average waiting time were calculated, each with its confidence interval. Resulting in the following:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/stats-01.png"&gt;&lt;img alt="Length of Queue" class="b-lazy" data-src="/blog/images/elevator-simulation/stats-01.png" src="https://elc.github.io/blog/images/elevator-simulation/stats-01-thumbnail.png" width="1054"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/stats-02.png"&gt;&lt;img alt="Waiting Time" class="b-lazy" data-src="/blog/images/elevator-simulation/stats-02.png" src="https://elc.github.io/blog/images/elevator-simulation/stats-02-thumbnail.png" width="1039"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Looking at the confidence interval of the waiting time, it is evident that FIFO and ALT2 were the worst and the other 3 options are quite similar. That's why Ranking and Selection was used to discern which was the best, increasing the sample size and the final result was the following (now the % of people leaving the queue is added):&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/stats-03.png"&gt;&lt;img alt="Length of Queue" class="b-lazy" data-src="/blog/images/elevator-simulation/stats-03.png" src="https://elc.github.io/blog/images/elevator-simulation/stats-03-thumbnail.png" width="928"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/stats-04.png"&gt;&lt;img alt="Waiting Time" class="b-lazy" data-src="/blog/images/elevator-simulation/stats-04.png" src="https://elc.github.io/blog/images/elevator-simulation/stats-04-thumbnail.png" width="928"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/stats-05.png"&gt;&lt;img alt="Leaving the Queue" class="b-lazy" data-src="/blog/images/elevator-simulation/stats-05.png" src="https://elc.github.io/blog/images/elevator-simulation/stats-05-thumbnail.png" width="928"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="demo"&gt;&lt;a class="toclink" href="#demo"&gt;Demo&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the final result, the initial menu is in Spanish but the rest of the GUI is in English. In case you can't run it you can go to the &lt;a href="#screenshots"&gt;screenshots&lt;/a&gt; section to see how it looks like and then run the model from a PC.&lt;/p&gt;
&lt;div class="iframe-container" style="padding-top: 71%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/elevator-simulation/simulation-anylogic-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;Also, you can embed this simulation in your website with the following snippet&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://elc.github.io/blog/iframes/elevator-simulation/simulation-anylogic-iframe.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although the results were contrary to the expected, it is worth mentioning that there are some limitations to take into consideration, which may vary the final result such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The university as an underground floor which wasn't modeled&lt;/li&gt;
&lt;li&gt;The second elevator wasn't modeled&lt;/li&gt;
&lt;li&gt;The electrical consumption of the alternatives is not considered&lt;/li&gt;
&lt;li&gt;The speed of the elevator is considered constant&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These limitations would result in a much more complex model but yield more accurate results. Also, notice that in this simulation the economical variable wasn't considered since it is tightly related to the electrical consumption.&lt;/p&gt;
&lt;h2 id="quote-and-citation"&gt;&lt;a class="toclink" href="#quote-and-citation"&gt;Quote and citation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you want to receive the source files of the model and/or quote this work, please feel free to send me an email at castanoezequielleonardo@gmail.com&lt;/p&gt;
&lt;h2 id="screenshots"&gt;&lt;a class="toclink" href="#screenshots"&gt;Screenshots&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The following are some screenshots of the running model&lt;/p&gt;
&lt;h3 id="main-screen"&gt;&lt;a class="toclink" href="#main-screen"&gt;Main Screen&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/simulation-part1.jpg"&gt;&lt;img alt="Main Screen" class="b-lazy" data-src="/blog/images/elevator-simulation/simulation-part1.jpg" src="https://elc.github.io/blog/images/elevator-simulation/simulation-part1-thumbnail.jpg" width="1439"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="elevator-control-panel"&gt;&lt;a class="toclink" href="#elevator-control-panel"&gt;Elevator Control Panel&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/simulation-part2.jpg"&gt;&lt;img alt="Elevator Panel" class="b-lazy" data-src="/blog/images/elevator-simulation/simulation-part2.jpg" src="https://elc.github.io/blog/images/elevator-simulation/simulation-part2-thumbnail.jpg" width="1440"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="student-behavior"&gt;&lt;a class="toclink" href="#student-behavior"&gt;Student Behavior&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/simulation-part3.jpg"&gt;&lt;img alt="Student Behavior" class="b-lazy" data-src="/blog/images/elevator-simulation/simulation-part3.jpg" src="https://elc.github.io/blog/images/elevator-simulation/simulation-part3-thumbnail.jpg" width="1440"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="2d-view"&gt;&lt;a class="toclink" href="#2d-view"&gt;2D View&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/simulation-part4.jpg"&gt;&lt;img alt="2D View" class="b-lazy" data-src="/blog/images/elevator-simulation/simulation-part4.jpg" src="https://elc.github.io/blog/images/elevator-simulation/simulation-part4-thumbnail.jpg" width="1441"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="2d-view-with-flow-density"&gt;&lt;a class="toclink" href="#2d-view-with-flow-density"&gt;2D View with Flow Density&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/simulation-part5.jpg"&gt;&lt;img alt="2D View with Flow Density" class="b-lazy" data-src="/blog/images/elevator-simulation/simulation-part5.jpg" src="https://elc.github.io/blog/images/elevator-simulation/simulation-part5-thumbnail.jpg" width="1439"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="waiting-time-histogram"&gt;&lt;a class="toclink" href="#waiting-time-histogram"&gt;Waiting Time Histogram&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/elevator-simulation/simulation-part6.jpg"&gt;&lt;img alt="Waiting Time Histogram" class="b-lazy" data-src="/blog/images/elevator-simulation/simulation-part6.jpg" src="https://elc.github.io/blog/images/elevator-simulation/simulation-part6-thumbnail.jpg" width="1440"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="number-of-people-vs-time-multiple-graphs"&gt;&lt;a class="toclink" href="#number-of-people-vs-time-multiple-graphs"&gt;Number of people vs Time (Multiple graphs)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a class="gallery" href="./blog/images/elevator-simulation/simulation-part7.jpg"&gt;&lt;img alt="Number of people multi-graph" class="b-lazy" data-src="/blog/images/elevator-simulation/simulation-part7.jpg" src="https://elc.github.io/blog/images/elevator-simulation/simulation-part7-thumbnail.jpg" width="1439"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="additional-resources"&gt;&lt;a class="toclink" href="#additional-resources"&gt;Additional Resources&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.anylogic.com/" target="_blank"&gt;AnyLogic Official Website&lt;/a&gt;: Here you can see the software features, case studies and examples.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.anylogic.com/resources/books/free-simulation-book-and-modeling-tutorials/" target="_blank"&gt;AnyLogic in Three Days: Modeling and Simulation Textbook&lt;/a&gt;: This was the book I used to learn the basics of the software although experimentation is also required to fully understand some topics.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.anylogic.com/" target="_blank"&gt;AnyLogic Cloud&lt;/a&gt;: This is the online repository of AnyLogic, where you can find several models from different topics. Free registration is required in order to see and run the models. Here is where the elevator simulation model is hosted.&lt;/li&gt;
&lt;/ul&gt;</content><category term="Simulation"></category><category term="Simulation"></category><category term="Programming"></category><category term="Math"></category><category term="AnyLogic"></category></entry><entry><title>Ordinary Differential Equations (ODE) with Python</title><link href="https://elc.github.io/posts/ordinary-differential-equations-with-python" rel="alternate"></link><published>2019-01-29T00:00:00-03:00</published><updated>2019-01-29T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2019-01-29:/posts/ordinary-differential-equations-with-python</id><summary type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/ode-python/ordinary-differential-equations-with-python-headerimage.png"&gt;&lt;img alt="ODE Header Image" class="b-lazy" data-src="/blog/images/ode-python/ordinary-differential-equations-with-python-headerimage.png" src="https://elc.github.io/blog/images/ode-python/ordinary-differential-equations-with-python-headerimage-thumbnail.png" width="1333"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;When I was at my 3rd year of University I have a complete subject about Ordinary Differential Equations and other similar topics. For that course we used Wolfram Mathematica throughout the year and I asked the teacher whether I can do it with Python, here you can see the results …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/ode-python/ordinary-differential-equations-with-python-headerimage.png"&gt;&lt;img alt="ODE Header Image" class="b-lazy" data-src="/blog/images/ode-python/ordinary-differential-equations-with-python-headerimage.png" src="https://elc.github.io/blog/images/ode-python/ordinary-differential-equations-with-python-headerimage-thumbnail.png" width="1333"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;When I was at my 3rd year of University I have a complete subject about Ordinary Differential Equations and other similar topics. For that course we used Wolfram Mathematica throughout the year and I asked the teacher whether I can do it with Python, here you can see the results.&lt;/p&gt;


&lt;p&gt;Of course in one year one solves a lot of differential equations but there were some problems that I think are really interesting and that rely on ordinary differential equations (ODE), numerical integration and reasoning. The year after, when I was in my 4th year, I had a subject called simulation where I learnt other techniques with another software and the focus was the process instead of the analytical form.&lt;/p&gt;
&lt;p&gt;The teacher showed us several situations one can model with ODE and each has its particularities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#economy-of-a-home"&gt;Economy of a Home&lt;/a&gt;: Piecewise Defined Derivatives&lt;/li&gt;
&lt;li&gt;&lt;a href="#sales-of-houses-and-air-conditionings"&gt;Sales of Houses and Air Conditionings&lt;/a&gt;: Systems of ODEs&lt;/li&gt;
&lt;li&gt;&lt;a href="#stock-control"&gt;Stock Control&lt;/a&gt;: Systems with oscillation (Underdamped, critically damped, overdamped and undamped)&lt;/li&gt;
&lt;li&gt;&lt;a href="#useful-life"&gt;Useful life in medicine&lt;/a&gt;: Start from a previous result&lt;/li&gt;
&lt;li&gt;&lt;a href="#foxes-and-rabbits"&gt;Predator and Prey Model&lt;/a&gt;: Non-linear relationships between variables&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of them are quite well-known but the aim of this post isn't introducing these models but rather how you can solve them with Python, I will also attach the interactive widgets so you can experiment with the models and see how they behave when you change the parameters. Also, I prepared a &lt;a href="https://elc.github.io/link/ode_python_binder"&gt;jupyter notebook&lt;/a&gt; where all these models are together, you can open it online and experiment directly. Additionally if you find any of the widgets useful you can embed them in your own website, at the end of each widget the code for doing so will be provided.&lt;/p&gt;
&lt;p&gt;This post will have some explanation of the models, and the equations, I won't focused on how to solve a ODE by hand since the focus is the computational aid one can have from open source tools.&lt;/p&gt;
&lt;p&gt;Requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jupyter.org/install" target="_blank"&gt;Jupyter&lt;/a&gt;: Notebook Interface&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.numpy.org/" target="_blank"&gt;Numpy&lt;/a&gt;: For array manipulation&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.scipy.org/" target="_blank"&gt;Scipy&lt;/a&gt;: For numerical integration&lt;/li&gt;
&lt;li&gt;&lt;a href="https://matplotlib.org/" target="_blank"&gt;Matplotlib&lt;/a&gt;: For visualization and animation&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="imports-and-setup"&gt;&lt;a class="toclink" href="#imports-and-setup"&gt;Imports and setup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before starting with the models themselves, we need to import some libraries, the imports are the same for all models so one can simply place this snippet at the top of the script/notebook. In this snipped the style for the sliders is also included in order to have the same look and feel in all the widgets&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# General Purpose&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;matplotlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pyplot&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;scipy.integrate&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;odeint&lt;/span&gt;

&lt;span class="c1"&gt;# Jupyter Specifics&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;IPython.display&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HTML&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ipywidgets.widgets&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Layout&lt;/span&gt;

&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;matplotlib&lt;/span&gt; &lt;span class="n"&gt;inline&lt;/span&gt;

&lt;span class="n"&gt;style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;description_width&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;150px&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;slider_layout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;99%&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="economy-of-a-home"&gt;&lt;a class="toclink" href="#economy-of-a-home"&gt;Economy of a Home&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A home economy (family) has a fixed income at the beginning of some periodic interval (usually a month), there are also two kind of outcomes, fixed costs and extraordinary expenses, which are proportional to the money at the moment. Additionally, the family decides to set apart some proportion of the income just for fixed costs. This way, when the capital of the family is below this amount, the extraordinary expenses are 0.&lt;/p&gt;
&lt;p&gt;The model has the following variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;initial_salary&lt;/code&gt; [$]: the amount of money for the income&lt;/li&gt;
&lt;li&gt;&lt;code&gt;savings_ratio&lt;/code&gt; [%]: Proportion of the income that will be the keep just for fixed costs&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fixed_costs&lt;/code&gt; [$]: The amount of money of fixed costs distributed per day&lt;/li&gt;
&lt;li&gt;&lt;code&gt;extraordinary_expenses&lt;/code&gt; [%]: Proportion of money that will be spend in extraordinary expenses.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;days&lt;/code&gt; [days]: The time interval until the next income&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notation for the equation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(x(t):\)&lt;/span&gt; Capital over time&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(x(0) =\)&lt;/span&gt; &lt;code&gt;initial_salary&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(s =\)&lt;/span&gt; &lt;code&gt;savings_ration * initial_salary&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(a =\)&lt;/span&gt; &lt;code&gt;fixed_costs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(b =\)&lt;/span&gt; &lt;code&gt;extraordinary_expenses&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the previously defined notation, the ordinary differential equation is as follows:&lt;/p&gt;
&lt;div class="math"&gt;$$
\frac{\mathrm{d} x}{\mathrm{d} t} = \left\{\begin{matrix} - a &amp;amp; x \leq  s \\ - b (x - s) &amp;amp; x &amp;gt; s  \end{matrix}\right.
$$&lt;/div&gt;
&lt;h3 id="widget"&gt;&lt;a class="toclink" href="#widget"&gt;Widget&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Below is the resulting model in action and then the code explain part by part.&lt;/p&gt;
&lt;div class="iframe-container" style="padding-top: 90%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/ode-python/home-economy-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;If you want to embed this widget in your blog/website, just add the following HTML:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://elc.github.io/blog/iframes/ode-python/home-economy-iframe.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="code"&gt;&lt;a class="toclink" href="#code"&gt;Code&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now I will comment part by part the code used, at the end of this section, I will place the full code for easy copy/paste&lt;/p&gt;
&lt;h4 id="function-definition"&gt;&lt;a class="toclink" href="#function-definition"&gt;Function Definition&lt;/a&gt;&lt;/h4&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_salary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savings_ratio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extraordinary_expenses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fixed_costs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;First, we defined a function called &lt;code&gt;main&lt;/code&gt; for easier use of &lt;code&gt;interact&lt;/code&gt; which will produce the interactive widget. After that, all the constants are calculated, in this case &lt;code&gt;saving_limit&lt;/code&gt; which is analogous to &lt;span class="math"&gt;\(s\)&lt;/span&gt; in the equation.&lt;/p&gt;
&lt;h4 id="ode-specifics"&gt;&lt;a class="toclink" href="#ode-specifics"&gt;ODE Specifics&lt;/a&gt;&lt;/h4&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;saving_limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;savings_ratio&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;initial_salary&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;capital&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;saving_limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;out_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;out_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;extraordinary_expenses&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;saving_limit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fixed_costs&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;out_rate&lt;/span&gt;

&lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linspace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;odeint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_salary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A nested function is defined (there could be better ways to do this but I find this the simplest), this function is the differential equation, it should take two parameters and return the value of &lt;span class="math"&gt;\(\frac{\mathrm{d} x}{\mathrm{d} t}\)&lt;/span&gt;. The first parameter can be used as the current value of &lt;span class="math"&gt;\(x\)&lt;/span&gt; for a given &lt;span class="math"&gt;\(t\)&lt;/span&gt;. For the numerical integration &lt;a href="https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.odeint.html" target="_blank"&gt;&lt;code&gt;scipy.integrate.odeint&lt;/code&gt;&lt;/a&gt; is used and that's why this format is required. Using a nested function has the advantage that its name doesn't conflict with the outer scope of the function containing it and that it has access to all the parameters the outer function has, avoiding unnecessary indirection due to reference (If you know a better way to implement this, let me know in the comments).&lt;/p&gt;
&lt;p&gt;Then the &lt;code&gt;time&lt;/code&gt; variable is defined and initialized, this will be the &lt;span class="math"&gt;\(t\)&lt;/span&gt; steps. We have basically two options here:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Define the &lt;strong&gt;start&lt;/strong&gt;, the &lt;strong&gt;end&lt;/strong&gt; and the &lt;strong&gt;number of steps&lt;/strong&gt;: For this &lt;a href="https://docs.scipy.org/doc/numpy/reference/generated/numpy.linspace.html" target="_blank"&gt;&lt;code&gt;numpy.linspace&lt;/code&gt;&lt;/a&gt; could be used&lt;/li&gt;
&lt;li&gt;Define the &lt;strong&gt;start&lt;/strong&gt;, the &lt;strong&gt;end&lt;/strong&gt; and the &lt;strong&gt;step&lt;/strong&gt;: For this &lt;a href="https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.arange.html" target="_blank"&gt;&lt;code&gt;numpy.arange&lt;/code&gt;&lt;/a&gt; could be used&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: It is important to note that this will determined how smooth the resulting function will be. Although at first it might seem that the integration step (usually denoted with &lt;span class="math"&gt;\(h\)&lt;/span&gt;) is implicitly defined here, that's not the case since, as you can see in the docs of &lt;code&gt;scipy.integrate.odeint&lt;/code&gt;, &lt;span class="math"&gt;\(h\)&lt;/span&gt; is determined by the solver in each iteration.&lt;/p&gt;
&lt;p&gt;Then the &lt;code&gt;scipy.integrate.odeint&lt;/code&gt; function is called with the function defined as a first parameter, the initial conditions as the second and the window time as the third. This function returns the solution array which will be later used for the plotting.&lt;/p&gt;
&lt;h4 id="graphics-specifics"&gt;&lt;a class="toclink" href="#graphics-specifics"&gt;Graphics Specifics&lt;/a&gt;&lt;/h4&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saving_limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;saving_limit&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Saving Limit&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Capital(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;horizontal&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
    &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticklabels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_yticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_salary&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_salary&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_salary&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Days&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Capital $&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;best&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Next, the graphics part, here matplotlib is used and this snipped is specific to this library but I will explain it in order to be self-contained (although I might produce a matplotlib tutorial in the future).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: I know there are plenty of plotting libraries, and many even more elegant and powerful than matplotlib but for this use case, where the complexity lies in the differential equation and not in the graphic itself, I believe it is more than enough. For complex graphics such as statistics or big data, I would recommend another library such as &lt;a href="https://github.com/bloomberg/bqplot" target="_blank"&gt;&lt;strong&gt;bqplot&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First we define a &lt;code&gt;figure&lt;/code&gt; and an &lt;code&gt;axes&lt;/code&gt; object, explicitly initializing the figure size through &lt;code&gt;figsize&lt;/code&gt;. Then a horizontal line with the label &lt;code&gt;Saving Limit&lt;/code&gt; is plot at the heigh of the &lt;code&gt;saving_limit&lt;/code&gt; and after that the solution is plot with the label &lt;code&gt;Capital(t)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The if-elif-else structure defines how many sticks there will be in the x-axis and if they should be place horizontal or vertically. Then the said sticks are plotted, the same occurs with the yticks. Then the limits for each axis and the labels for each axis are set and finally, the legend position is defined and the grid is added.&lt;/p&gt;
&lt;p&gt;Then when &lt;code&gt;plt.show()&lt;/code&gt; is called the figure is generated and showed in the screen.&lt;/p&gt;
&lt;h4 id="interaction-specifics"&gt;&lt;a class="toclink" href="#interaction-specifics"&gt;Interaction Specifics&lt;/a&gt;&lt;/h4&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_salary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;25000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Initial Salary&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;savings_ration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Savings Ratio&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;extraordinary_expenses&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.005&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Extraordinary Expenses&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;fixed_costs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Fixed Costs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Total Number of Days&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, the code for the interaction, here the &lt;code&gt;interact&lt;/code&gt; function from &lt;a href="https://ipywidgets.readthedocs.io/en/stable/" target="_blank"&gt;&lt;code&gt;ipywidgets&lt;/code&gt;&lt;/a&gt; is used. A separate slider is used for each parameter with the default parameters set for a nice default visualization, with a description and the style and layout is used from the initialization cells.&lt;/p&gt;
&lt;h3 id="full-code"&gt;&lt;a class="toclink" href="#full-code"&gt;Full code&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_salary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;savings_ratio&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extraordinary_expenses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fixed_costs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;saving_limit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;savings_ratio&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;initial_salary&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;capital&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;saving_limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;out_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;out_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;extraordinary_expenses&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;capital&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;saving_limit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fixed_costs&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;out_rate&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linspace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;odeint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_salary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;#Graphic details&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saving_limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;saving_limit&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Saving Limit&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Capital(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;horizontal&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticklabels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_yticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_salary&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_salary&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_salary&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Days&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Capital $&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;best&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_salary&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;25000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Initial Salary&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;savings_ratio&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Savings Ratio&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;extraordinary_expenses&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.005&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Extraordinary Expenses&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;fixed_costs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Fixed Costs&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Total Number of Days&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="sales-of-houses-and-air-conditionings"&gt;&lt;a class="toclink" href="#sales-of-houses-and-air-conditionings"&gt;Sales of Houses and Air Conditionings&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In a city there are houses and air conditionings (AC) for sale and it's known that these are complementary goods, which means that if the sales of one increase the sales of the other will also increase. The number of houses sales is proportional to the number of houses that weren't sold yet and the number of AC sales is proportional to the houses sold that doesn't yet have an AC.&lt;/p&gt;
&lt;p&gt;The model has the following variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;initial_houses&lt;/code&gt; [houses]: Number of Houses initially sold, could be 0.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;initial_ac&lt;/code&gt; [AC]: Number of air conditionings sold, could be 0 and should be less than &lt;code&gt;initial_houses&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;avg_time_house&lt;/code&gt; [days]: Average number of days to sell a house.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;avg_time_ac&lt;/code&gt; [days]: Average number of days to sell an AC.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;total_houses&lt;/code&gt; [houses]: Total number of Houses for sale.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;days&lt;/code&gt; [days]: The time interval until the next income&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notation for the equation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(x(t):\)&lt;/span&gt; Number of sold Houses&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(y(t):\)&lt;/span&gt; Number of sold Air Conditionings&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(x(0) =\)&lt;/span&gt; &lt;code&gt;initial_houses&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(y(0) =\)&lt;/span&gt; &lt;code&gt;initial_ac&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(h =\)&lt;/span&gt; &lt;code&gt;total_houses&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(a =\)&lt;/span&gt; &lt;code&gt;avg_time_house&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(b =\)&lt;/span&gt; &lt;code&gt;avg_time_ac&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the previously defined notation, the ordinary differential equation is as follows:&lt;/p&gt;
&lt;div class="math"&gt;$$
\left\{\begin{matrix} \frac{\mathrm{d} x}{\mathrm{d} t} =\frac{1}{a} (h - x) \\\\ \frac{\mathrm{d} y}{\mathrm{d} t} =\frac{1}{b} (x - y)  \end{matrix}\right.
$$&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The last scenario was a first-order differential equation and in this case it a system of two first-order differential equations, the package we are using, &lt;code&gt;scipy.integrate.odeint&lt;/code&gt; can only integrate first-order differential equations but this doesn't limit the number of problems one can solve with it since &lt;strong&gt;any ODE of order greater than one can be [and usually is] rewritten as system of first order ODEs&lt;/strong&gt; &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h3 id="widget_1"&gt;&lt;a class="toclink" href="#widget_1"&gt;Widget&lt;/a&gt;&lt;/h3&gt;
&lt;div class="iframe-container" style="padding-top: 86%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/ode-python/houses-air_conditioning-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;Embed this widget in your website:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://elc.github.io/blog/iframes/ode-python/houses-air_conditioning-iframe.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="code_1"&gt;&lt;a class="toclink" href="#code_1"&gt;Code&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In this scenario and the followings the code will be explain where it differs from the first example to avoid unnecesary repetition&lt;/p&gt;
&lt;h4 id="ode-specifics_1"&gt;&lt;a class="toclink" href="#ode-specifics_1"&gt;ODE Specifics&lt;/a&gt;&lt;/h4&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
    &lt;span class="n"&gt;dydt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;avg_time_house&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_houses&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;    &lt;span class="c1"&gt;# dx/dt: Change in the House sales&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;avg_time_ac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="c1"&gt;# dx/dt: Change in the AC sales&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dydt&lt;/span&gt;

&lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linspace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;initial_conditions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;initial_houses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_ac&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;odeint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_conditions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case the constants &lt;code&gt;avg_time_house&lt;/code&gt; and &lt;code&gt;avg_time_ac&lt;/code&gt; are used directly inside the function since it is much clearer this way. To define a system of ODEs, first the initial condition should be a list, each element of the list represents the initial condition for each of the variables. The nested function also changes a bit, in order to work, the first parameter would also be a list so it is necessary to unpack it into the variables and then a variable &lt;code&gt;dydt&lt;/code&gt; is used (the &lt;code&gt;dydt&lt;/code&gt; name doesn't refer to the variable &lt;code&gt;y&lt;/code&gt; but rather is the convention in &lt;code&gt;scipy&lt;/code&gt;) to represent the system where each element is the left side of each equation (in canonical form).&lt;/p&gt;
&lt;p&gt;Although it may differ from PEP8 (Python style for coding), I prefer to split the elements one per line to improve readability. Finally the &lt;code&gt;dydt&lt;/code&gt; variable is returned. The definition of &lt;code&gt;time&lt;/code&gt; is the same as previously seen and the solution variable is now a nested array containing the solution for both variables. This is specially useful when plotting.&lt;/p&gt;
&lt;h4 id="graphics-specifics_1"&gt;&lt;a class="toclink" href="#graphics-specifics_1"&gt;Graphics Specifics&lt;/a&gt;&lt;/h4&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Houses(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Air Conditionings(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These are the only lines that differ in which instead of plotting the &lt;code&gt;solution&lt;/code&gt; variable, the &lt;a href="https://docs.scipy.org/doc/numpy-1.13.0/reference/arrays.indexing.html" target="_blank"&gt;numpy indexing and slicing syntax&lt;/a&gt; is used to easily split the results from each of the variables.&lt;/p&gt;
&lt;h3 id="full-code_1"&gt;&lt;a class="toclink" href="#full-code_1"&gt;Full code&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initial_houses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_ac&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;avg_time_house&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;avg_time_ac&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_houses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
        &lt;span class="n"&gt;dydt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;avg_time_house&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_houses&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# dx/dt: Change in the House sales&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;avg_time_ac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;             &lt;span class="c1"&gt;# dx/dt: Change in the AC sales&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dydt&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linspace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;initial_conditions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;initial_houses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_ac&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;odeint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_conditions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;#Graphic details&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Houses(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Air Conditionings(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total_houses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_houses&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Total Houses&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;horizontal&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticklabels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_yticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_houses&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_houses&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_houses&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Months&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Units&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;best&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_houses&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Initial sold Houses&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;initial_ac&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Initial sold AC&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;total_houses&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Total Houses&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;avg_time_house&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Time for House&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;avg_time_ac&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Time for AC&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;360&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Total Number of Days&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="stock-control"&gt;&lt;a class="toclink" href="#stock-control"&gt;Stock Control&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A company wants a desired stock, they started with an initial stock and they work with a provider which sends deliveries goods through sales orders. The company asks the provider each day a sales order proportional to the missing or surplus quantity to the desired stock and the market demand. The provider deliver the goods according to the sales order with a constant delay. Finally, the market demand is consider constant. The company wants to know how their stock and their request to the provider will behave and they will try to avoid alternating behavior (oscillation in stock).&lt;/p&gt;
&lt;p&gt;The model has the following variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;desired_stock&lt;/code&gt; [goods]: Amount of stock the company wants to have.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;initial_stock&lt;/code&gt; [goods]: The initial amount of stock of the company.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;initial_orders&lt;/code&gt; [goods]: initial amount of goods asked in sales orders.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stock_control&lt;/code&gt; [%]: Proportion of the missing/surplus stock to ask to the provider.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;market_demand&lt;/code&gt; [goods]: The daily demand of the market&lt;/li&gt;
&lt;li&gt;&lt;code&gt;provider_delay&lt;/code&gt; [days]: The number of days of the provider delay.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;days&lt;/code&gt; [days]: The total number of days the model will analyse.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notation for the equation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(x(t):\)&lt;/span&gt; Number of goods in stock&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(y(t):\)&lt;/span&gt; Number of pending sales order sent to the provider&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(x(0) =\)&lt;/span&gt; &lt;code&gt;initial_stock&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(y(0) =\)&lt;/span&gt; &lt;code&gt;initial_orders&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(s =\)&lt;/span&gt; &lt;code&gt;desired_stock&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(d =\)&lt;/span&gt; &lt;code&gt;market_demand&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(k =\)&lt;/span&gt; &lt;code&gt;stock_control&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(p =\)&lt;/span&gt; &lt;code&gt;provider_delay&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the previously defined notation, the ordinary differential equation is as follows:&lt;/p&gt;
&lt;div class="math"&gt;$$
\left\{\begin{matrix} \frac{\mathrm{d} x}{\mathrm{d} t} =&amp;amp;   \frac{1}{p} y - d \\\\ \frac{\mathrm{d} y}{\mathrm{d} t} =&amp;amp; - \frac{1}{p} y + d + k ( s - x ) \end{matrix}\right.
$$&lt;/div&gt;
&lt;h3 id="widget_2"&gt;&lt;a class="toclink" href="#widget_2"&gt;Widget&lt;/a&gt;&lt;/h3&gt;
&lt;div class="iframe-container" style="padding-top: 97%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/ode-python/stock-control-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;Embed this widget in your website:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://elc.github.io/blog/iframes/ode-python/stock-control-iframe.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="code_2"&gt;&lt;a class="toclink" href="#code_2"&gt;Code&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id="ode-specifics_2"&gt;&lt;a class="toclink" href="#ode-specifics_2"&gt;ODE Specifics&lt;/a&gt;&lt;/h4&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;
    &lt;span class="n"&gt;dydt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;provider_delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;market_demand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                                        &lt;span class="c1"&gt;# dx/dt: Change in Stock&lt;/span&gt;
      &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;provider_delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;market_demand&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;stock_control&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;desired_stock&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# dy/dt: Change in Requests&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dydt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This time the code is only changed in the variables names and the equations but it is very similar to the previous example, the particularity of this model doesn't lie in the code but rather in the behavior, since it can show the differences between an oscillation behavior and a damped one. Going through all kinds of possibilities such as underdamped, overdamped, critically damped and undamped. I encourage you to experiment with the parameters in the widget.&lt;/p&gt;
&lt;h3 id="full-code_2"&gt;&lt;a class="toclink" href="#full-code_2"&gt;Full code&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;desired_stock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_stock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_orders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stock_control&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;market_demand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;provider_delay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;v0&lt;/span&gt;
        &lt;span class="n"&gt;dydt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;provider_delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;market_demand&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                                        &lt;span class="c1"&gt;# dx/dt: Change in Stock&lt;/span&gt;
          &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;provider_delay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;market_demand&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;stock_control&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;desired_stock&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# dy/dt: Change in Requests&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dydt&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linspace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;initial_conditions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;initial_stock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_orders&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;odeint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_conditions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;#Graphic details&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Stock(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Requests(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;desired_stock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desired_stock&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Desired Stock&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;horizontal&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticklabels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.05&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Days&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Units&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;best&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desired_stock&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Desired Stock&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;initial_stock&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Initial Stock&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;initial_orders&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Initial Requests&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;stock_control&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Stock Control&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;market_demand&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Market Demand&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;provider_delay&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Provider Delay&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;360&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Total Number of Days&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="useful-life"&gt;&lt;a class="toclink" href="#useful-life"&gt;Useful Life&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A patient takes a certain drug with a recipe, the recipe says how many milligrams the patient should have per intake, how often the intakes should be and how many. Additionally the drug itself provides information about its useful life which helps to determine the optimal interval between intakes. It's also known that the useful life of the drug follows a natural decay.&lt;/p&gt;
&lt;p&gt;The model has the following variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;useful_life&lt;/code&gt; [hs]: Duration of the useful life of the drug&lt;/li&gt;
&lt;li&gt;&lt;code&gt;intake_mg&lt;/code&gt; [mg]: Amount of milligrams per intake.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;intake_interval&lt;/code&gt; [hs]: Time interval between intakes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;intake_number&lt;/code&gt; [1]: Number of intakes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hours&lt;/code&gt; [hours]: The total number of hours the model will analyse.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notation for the equation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(x(t):\)&lt;/span&gt; Milligrams of drug in the body&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(x(0) =\)&lt;/span&gt; &lt;code&gt;intake_mg&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(a =\)&lt;/span&gt; &lt;code&gt;useful_life&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the previously defined notation, the ordinary differential equation is as follows:&lt;/p&gt;
&lt;div class="math"&gt;$$
\frac{\mathrm{d} x}{\mathrm{d} t} = - \frac{1}{a} ln(2) y
$$&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; the &lt;span class="math"&gt;\(ln(2)\)&lt;/span&gt; is part of the natural decay formula.&lt;/p&gt;
&lt;h3 id="widget_3"&gt;&lt;a class="toclink" href="#widget_3"&gt;Widget&lt;/a&gt;&lt;/h3&gt;
&lt;div class="iframe-container" style="padding-top: 89%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/ode-python/useful-life-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://elc.github.io/blog/iframes/ode-python/useful-life-iframe.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="code_3"&gt;&lt;a class="toclink" href="#code_3"&gt;Code&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id="ode-specifics_3"&gt;&lt;a class="toclink" href="#ode-specifics_3"&gt;ODE Specifics&lt;/a&gt;&lt;/h4&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;useful_life&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="c1"&gt;# dy/dt: Change of mg&lt;/span&gt;

&lt;span class="n"&gt;intake_hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;intake_interval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intake_number&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="n"&gt;initial_condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intake_mg&lt;/span&gt;
&lt;span class="n"&gt;times&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;solutions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;intake_time&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;intake_hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intake_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intake_time&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;intake_interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;odeint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_condition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;initial_condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;intake_mg&lt;/span&gt;

    &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;solutions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;intake_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intake_hours&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;intake_interval&lt;/span&gt;
&lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intake_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intake_time&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;intake_interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;odeint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_condition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;solutions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This model doesn't introduces complexity in the ODE but rather in the way one can model the successive intakes. It is usually helpful to keep this 'iteration logic' independent from the ODE itself, that's why no particular changes are needed in the equations.&lt;/p&gt;
&lt;p&gt;There are many ways for achieving this but the one I used is the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a list with all the intake hours&lt;/li&gt;
&lt;li&gt;Create an empty list, &lt;code&gt;times&lt;/code&gt;, for the times&lt;/li&gt;
&lt;li&gt;Create an empty list, &lt;code&gt;solutions&lt;/code&gt; for the solutions&lt;/li&gt;
&lt;li&gt;Iterate through that list&lt;ol&gt;
&lt;li&gt;Create a &lt;code&gt;time&lt;/code&gt; array starting in the time iterated and ended in the time iterated + the &lt;code&gt;intake_interval&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Solve the ODE with the &lt;code&gt;initial_condition&lt;/code&gt; and the previously created &lt;code&gt;time&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Update the value of the &lt;code&gt;initial_conditions&lt;/code&gt; with the final solution&lt;/li&gt;
&lt;li&gt;Append the &lt;code&gt;solution&lt;/code&gt; list to the end of the &lt;code&gt;solutions&lt;/code&gt; list&lt;/li&gt;
&lt;li&gt;Append the &lt;code&gt;time&lt;/code&gt; list to the end of the &lt;code&gt;times&lt;/code&gt; list&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;time&lt;/code&gt; array starting from the last the last time of intakes to 10 times the &lt;code&gt;intake_interval&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Solve the ODE again with a longer interval to see how it behaves after the iterations&lt;/li&gt;
&lt;li&gt;Append the &lt;code&gt;solution&lt;/code&gt; list to the end of the &lt;code&gt;solutions&lt;/code&gt; list&lt;/li&gt;
&lt;li&gt;Append the &lt;code&gt;time&lt;/code&gt; list to the end of the &lt;code&gt;times&lt;/code&gt; list&lt;/li&gt;
&lt;li&gt;Proceed to Plotting&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This approach consist in solving several ODEs, each of which receives the final solution of the previous as its initial conditions.&lt;/p&gt;
&lt;h3 id="full-code_3"&gt;&lt;a class="toclink" href="#full-code_3"&gt;Full code&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;useful_life&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intake_mg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intake_interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intake_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;useful_life&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="c1"&gt;# dy/dt: Change of mg&lt;/span&gt;

    &lt;span class="n"&gt;intake_hours&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;intake_interval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intake_number&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;initial_condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intake_mg&lt;/span&gt;
    &lt;span class="n"&gt;times&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;solutions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;intake_time&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;intake_hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intake_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intake_time&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;intake_interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;odeint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_condition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;initial_condition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;intake_mg&lt;/span&gt;

        &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;solutions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


    &lt;span class="n"&gt;intake_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intake_hours&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;intake_interval&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intake_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;intake_time&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;intake_interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;odeint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_condition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;solutions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;#Graphic details&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solutions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Concentration in the Body(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;horizontal&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticklabels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hours&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solutions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.05&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hours&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Concentration&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;best&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;useful_life&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;3.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Useful Life (hs)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;intake_mg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Milligrams per Intake&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;intake_interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Hours between Intakes&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;intake_number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Number of Intakes&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;hours&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;240&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Total number of Hours&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="foxes-and-rabbits"&gt;&lt;a class="toclink" href="#foxes-and-rabbits"&gt;Foxes and Rabbits&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is the model known as predator–prey or Lotka–Volterra equations. There are two species, a predator and a prey, like foxes and rabbits. Each has a certain birthrate and a deathrate. The birthrate of the prey is proportional to its current population and the birthrate of the predator is proportional to both its population and the prey population. The deathrate of the prey is proportional to both its population and the predator population and the deathrate of the predator is proportional to its population.&lt;/p&gt;
&lt;p&gt;The model has the following variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rabbits_birthrate&lt;/code&gt; [1]: Duration of the useful life of the drug&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rabbits_deathrate&lt;/code&gt; [1]: Amout of miligrams per intake.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;foxes_birthrate&lt;/code&gt; [1]: Time interval between intakes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;foxes_deathrate&lt;/code&gt; [1]: Number of intakes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;initial_rabbits&lt;/code&gt; [rabbits]: Number of intakes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;initial_foxes&lt;/code&gt; [foxes]: Number of intakes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;days&lt;/code&gt; [days]: The total number of days the model will analyse.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Notation for the equation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="math"&gt;\(x(t):\)&lt;/span&gt; Population of Rabbits over time&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(x(0) =\)&lt;/span&gt; &lt;code&gt;initial_rabbits&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(y(t):\)&lt;/span&gt; Population of Foxes over time&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(y(0) =\)&lt;/span&gt; &lt;code&gt;initial_foxes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(a =\)&lt;/span&gt; &lt;code&gt;rabbits_birthrate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(b =\)&lt;/span&gt; &lt;code&gt;rabbits_deathrate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(c =\)&lt;/span&gt; &lt;code&gt;foxes_birthrate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="math"&gt;\(d =\)&lt;/span&gt; &lt;code&gt;foxes_deathrate&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the previously defined notation, the ordinary differential equation is as follows:&lt;/p&gt;
&lt;div class="math"&gt;$$
\left\{\begin{matrix} \frac{\mathrm{d} x}{\mathrm{d} t} =&amp;amp; a x &amp;amp;-&amp;amp; bxy\\\\ \frac{\mathrm{d} y}{\mathrm{d} t} =&amp;amp; cxy &amp;amp;-&amp;amp; dy \end{matrix}\right.
$$&lt;/div&gt;
&lt;p&gt;Or more concisely:&lt;/p&gt;
&lt;div class="math"&gt;$$
\left\{\begin{matrix} \frac{\mathrm{d} x}{\mathrm{d} t} =&amp;amp; x (a - by)\\\\ \frac{\mathrm{d} y}{\mathrm{d} t} =&amp;amp; y (cx - d) \end{matrix}\right.
$$&lt;/div&gt;
&lt;h3 id="widget_4"&gt;&lt;a class="toclink" href="#widget_4"&gt;Widget&lt;/a&gt;&lt;/h3&gt;
&lt;div class="iframe-container" style="padding-top: 97%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/ode-python/foxes-rabbits-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;https://elc.github.io/blog/iframes/ode-python/foxes-rabbits-iframe.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;iframe&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="code_4"&gt;&lt;a class="toclink" href="#code_4"&gt;Code&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id="ode-specifics_4"&gt;&lt;a class="toclink" href="#ode-specifics_4"&gt;ODE Specifics&lt;/a&gt;&lt;/h4&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
    &lt;span class="n"&gt;dydt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;rabbits_birthrate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;     &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;rabbits_deathrate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# dx/dy: Change in Rabbits&lt;/span&gt;
        &lt;span class="n"&gt;foxes_birthrate&lt;/span&gt;   &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;foxes_deathrate&lt;/span&gt;   &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;      &lt;span class="c1"&gt;# dy/dt: Change in Foxes&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dydt&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case the equations are similar to the houses and air conditioning example but the main difference is that the equations are non-linear since they include &lt;span class="math"&gt;\(xy\)&lt;/span&gt;, this implies that finding an analytical solution will be much harder but for the numerical integration the problem isn't any more difficult.&lt;/p&gt;
&lt;h4 id="graphics-specifics_2"&gt;&lt;a class="toclink" href="#graphics-specifics_2"&gt;Graphics Specifics&lt;/a&gt;&lt;/h4&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Rabbits(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;foxes(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Foxes vs Rabbits&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This scenario also introduces some variations in the plotting since, it is quite useful to have a parametric plot of the variables, where, instead of using the &lt;code&gt;time&lt;/code&gt; as independent variables the two variables are plot. This is simply achieved with &lt;code&gt;ax.plot(solution[:, 0], solution[:, 1], label='Foxes vs Rabbits')&lt;/code&gt; also, this model uses subplots and that's why the &lt;code&gt;axes&lt;/code&gt; list is used to place the plots one next to the other. This parametric plot also reveals an interesting fact, since the parametric plot is a closed curve, it implies that the functions are periodic which really reflect the natural behavior of predators and preys.&lt;/p&gt;
&lt;h3 id="full-code_4"&gt;&lt;a class="toclink" href="#full-code_4"&gt;Full code&lt;/a&gt;&lt;/h3&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rabbits_birthrate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rabbits_deathrate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;foxes_birthrate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;foxes_deathrate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_rabbits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_foxes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;
        &lt;span class="n"&gt;dydt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;rabbits_birthrate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;     &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;rabbits_deathrate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# dx/dy: Change in Rabbits&lt;/span&gt;
            &lt;span class="n"&gt;foxes_birthrate&lt;/span&gt;   &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;foxes_deathrate&lt;/span&gt;   &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;      &lt;span class="c1"&gt;# dy/dt: Change in Foxes&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;dydt&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;initial_conditions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;initial_rabbits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_foxes&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;solution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;odeint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;initial_conditions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;#Graphic details&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Rabbits(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Foxes(t)&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;horizontal&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
        &lt;span class="n"&gt;rotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;vertical&amp;quot;&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticklabels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.05&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Time&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Population&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;best&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Foxes vs Rabbits&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.05&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;solution&lt;/span&gt;&lt;span class="p"&gt;[:,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;1.05&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Rabbits&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Foxes&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;legend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;best&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tight_layout&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rabbits_birthrate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Birth Rate of Rabbits&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;rabbits_deathrate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Death Rate of Rabbits&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;foxes_birthrate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Birth Rate of Foxes&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;foxes_deathrate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Death Rate of Foxes&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;initial_rabbits&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Initial Rabbits&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;initial_foxes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Initial Foxes&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
               &lt;span class="n"&gt;days&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;365&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Total number of Days&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;slider_layout&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Uri M. Ascher; Linda R. Petzold (1998). Computer Methods for Ordinary Differential Equations and Differential-Algebraic Equations. SIAM. p. 5.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;script type="text/javascript"&gt;if (!document.getElementById('mathjaxscript_pelican_#%@#$@#')) {
    var align = "center",
        indent = "0em",
        linebreak = "false";

    if (true) {
        align = (screen.width &lt; 768) ? "left" : align;
        indent = (screen.width &lt; 768) ? "0em" : indent;
        linebreak = (screen.width &lt; 768) ? 'true' : linebreak;
    }

    var mathjaxscript = document.createElement('script');
    mathjaxscript.id = 'mathjaxscript_pelican_#%@#$@#';
    mathjaxscript.type = 'text/javascript';
    mathjaxscript.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML';
    mathjaxscript[(window.opera ? "innerHTML" : "text")] =
        "MathJax.Hub.Config({" +
        "    config: ['MMLorHTML.js']," +
        "    TeX: { extensions: ['AMSmath.js','AMSsymbols.js','noErrors.js','noUndefined.js'], equationNumbers: { autoNumber: 'AMS' } }," +
        "    jax: ['input/TeX','input/MathML','output/HTML-CSS']," +
        "    extensions: ['tex2jax.js','mml2jax.js','MathMenu.js','MathZoom.js']," +
        "    displayAlign: '"+ align +"'," +
        "    displayIndent: '"+ indent +"'," +
        "    showMathMenu: true," +
        "    messageStyle: 'normal'," +
        "    tex2jax: { " +
        "        inlineMath: [ ['\\\\(','\\\\)'] ], " +
        "        displayMath: [ ['$$','$$'] ]," +
        "        processEscapes: true," +
        "        preview: 'TeX'," +
        "    }, " +
        "    'HTML-CSS': { " +
        "        styles: { '.MathJax_Display, .MathJax .mo, .MathJax .mi, .MathJax .mn': {color: 'inherit ! important'} }," +
        "        linebreaks: { automatic: "+ linebreak +", width: '90% container' }," +
        "    }, " +
        "}); " +
        "if ('default' !== 'default') {" +
            "MathJax.Hub.Register.StartupHook('HTML-CSS Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax['HTML-CSS'].FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
            "MathJax.Hub.Register.StartupHook('SVG Jax Ready',function () {" +
                "var VARIANT = MathJax.OutputJax.SVG.FONTDATA.VARIANT;" +
                "VARIANT['normal'].fonts.unshift('MathJax_default');" +
                "VARIANT['bold'].fonts.unshift('MathJax_default-bold');" +
                "VARIANT['italic'].fonts.unshift('MathJax_default-italic');" +
                "VARIANT['-tex-mathit'].fonts.unshift('MathJax_default-italic');" +
            "});" +
        "}";
    (document.body || document.getElementsByTagName('head')[0]).appendChild(mathjaxscript);
}
&lt;/script&gt;</content><category term="Simulation"></category><category term="Simulation"></category><category term="Math"></category><category term="Python"></category><category term="Scipy"></category><category term="ODE"></category></entry><entry><title>Visualizing Math: A Guide to Creating Times Table Animations with Python</title><link href="https://elc.github.io/posts/times-tables" rel="alternate"></link><published>2019-01-22T00:00:00-03:00</published><updated>2019-01-22T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2019-01-22:/posts/times-tables</id><summary type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/times_tables/times-tables-headerimage.png"&gt;&lt;img alt="Times Table Header Image" class="b-lazy" data-src="/blog/images/times_tables/times-tables-headerimage.png" src="https://elc.github.io/blog/images/times_tables/times-tables-headerimage-thumbnail.png" width="1120"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Explore the mesmerizing patterns of times tables with Python! In this blog post,
we present an alternative implementation to the famous Mathologer's video where
beautiful patterns emerge from times tables. Burkard highlights how stunning
patterns arise from these tables and utilizes Wolfram Mathematica to demonstrate
these patterns in greater detail …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/times_tables/times-tables-headerimage.png"&gt;&lt;img alt="Times Table Header Image" class="b-lazy" data-src="/blog/images/times_tables/times-tables-headerimage.png" src="https://elc.github.io/blog/images/times_tables/times-tables-headerimage-thumbnail.png" width="1120"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Explore the mesmerizing patterns of times tables with Python! In this blog post,
we present an alternative implementation to the famous Mathologer's video where
beautiful patterns emerge from times tables. Burkard highlights how stunning
patterns arise from these tables and utilizes Wolfram Mathematica to demonstrate
these patterns in greater detail. This blog post aims to showcase a similar
implementation using Python.&lt;/p&gt;


&lt;p&gt;For those unfamiliar with the concept, it is recommended to view the video that
served as inspiration for this post. It provides a comprehensive explanation of
what Times Tables are.&lt;/p&gt;
&lt;iframe width="900" height="506" src="https://www.youtube.com/embed/qhbuKbxJsk8" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen&gt;&lt;/iframe&gt;

&lt;p&gt;This post provides an alternative approach to generate similar animations to the
ones seen in the video, using Python and its libraries such as Matplotlib and
IPython.&lt;/p&gt;
&lt;p&gt;The following animations were created using Python and its supporting libraries.&lt;/p&gt;
&lt;p&gt;&lt;img alt="times-table-2-100" class="narrow b-lazy" data-src="/blog/images/times_tables/times-tables-2-100.png" src="https://elc.github.io/blog/images/times_tables/times-tables-2-100-thumbnail.png" width="613"&gt;&lt;/p&gt;
&lt;p&gt;Bringing this captivating video to life with Python is made easy with the help
of a Jupyter Notebook. Explore the examples and discover the beauty of Times
Tables for yourself by following along. With all the necessary dependencies
already installed, the &lt;a href="https://elc.github.io/link/times_table_binder" target="_blank"&gt;Jupyter
Notebook&lt;/a&gt; is
the perfect platform for experimentation and hands-on learning&lt;/p&gt;
&lt;p&gt;In this post, multiple examples are provided, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A static version, as shown above An interactive, parametric version where you
can experiment by adjusting values with sliders&lt;/li&gt;
&lt;li&gt;An animated construction, line by line, where the factor and number of points
  remain fixed, but each line is plotted one at a time&lt;/li&gt;
&lt;li&gt;An animated construction, point by point, where the factor and lines are
  fixed, but the number of points increases with each frame&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An animated construction, factor by factor, where the lines and number of
  points remain fixed, but the factor increases, first in monochrome and then
  with a rainbow effect.n with the rainbow effect seen in the video.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: It's important to note that after exploring each scenario, both an
interactive and a static representation of the code will be provided. The
interactive version is built using Jupyter widgets, allowing you to adjust
parameters and see the results in real-time. However, this also means that
each time the sliders are moved, the full animation needs to be
re-calculated, so some patience is required. On the other hand, the static
representation is optimized for faster display and can be useful for
low-speed connections. It should be noted that the static representation
cannot be adjusted or experimented with.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Jupyter: Notebook Interface&lt;/li&gt;
&lt;li&gt;Numpy: For array manipulation&lt;/li&gt;
&lt;li&gt;Matplotlib: For visualization and animation&lt;/li&gt;
&lt;li&gt;ffmpeg (Optional): For exporting the animation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In order to produce these images and animations, the code should be split in 4 parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Import all the necesary libraris&lt;/li&gt;
&lt;li&gt;Define all the auxiliary functions&lt;/li&gt;
&lt;li&gt;Plot the animations&lt;/li&gt;
&lt;li&gt;Export (optional)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="initialization"&gt;&lt;a class="toclink" href="#initialization"&gt;Initialization&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is recommended to place all imports at the beginning of the document for
better organization and maintenance. This also helps to clearly identify the
required tools. In this instance, there are both general purpose imports and
those specific to Jupyter. To utilize the code outside of Jupyter, it may need
to be modified to remove Jupyter-specific components. This ensures the code can
run as a standalone script.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# General Purpose&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;colorsys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;matplotlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rc&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;matplotlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pyplot&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;matplotlib.collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LineCollection&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;matplotlib.lines&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Line2D&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;numpy.typing&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;npt&lt;/span&gt;

&lt;span class="c1"&gt;# Jupyter Specifics&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;ipywidgets.widgets&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Layout&lt;/span&gt;

&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;matplotlib&lt;/span&gt; &lt;span class="n"&gt;inline&lt;/span&gt;
&lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;animation&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;html5&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="basic-functions"&gt;&lt;a class="toclink" href="#basic-functions"&gt;Basic Functions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With all the necessary imports in place, it's time to define a few functions
that will bring this project to life. These functions include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A function to calculate the points around a circle&lt;/li&gt;
&lt;li&gt;A function to generate each of the lines&lt;/li&gt;
&lt;li&gt;A function to plot the labels and points on the circle&lt;/li&gt;
&lt;li&gt;A function to plot the lines on the circle&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The first function, named &lt;code&gt;points_around_circle&lt;/code&gt;, uses polar coordinates to
determine a specified number of points around a circle of radius 1. The use of
numpy in this calculation enhances its performance.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;points_around_circle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;npt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NDArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;theta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;linspace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;theta&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;theta&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ys&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The second function pertains to the generation of lines. Given a list of points,
this function generates a new line.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_lines_from_points&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;npt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NDArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;npt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NDArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;arange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;

    &lt;span class="n"&gt;line_starts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;
    &lt;span class="n"&gt;line_ends&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;line_starts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;astype&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;line_ends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line_starts&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, the line in numpy format is not directly plotable. To translate the
numpy array into a data structure compatible with matplotlib, a LineCollection
is used. The function &lt;code&gt;generate_line_collection&lt;/code&gt; not only generates the line
collection, but also specifies the color based on the HSV format. This
capability will come in handy when creating the final animation.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_line_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;npt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NDArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Optional&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;LineCollection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_lines_from_points&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;color_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;colorsys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hsv_to_rgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;LineCollection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;color_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="static-version"&gt;&lt;a class="toclink" href="#static-version"&gt;Static Version&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With all the required functions defined, plotting a static version of the data
is straightforward. Simply generate the axis object and call the functions in
the appropriate order, and the image will be generated. This approach is useful
for quickly experimenting with a fixed number of factors and points.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plot_static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;number_of_points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;points_around_circle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;number_of_points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_line_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gca&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;off&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Points: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;number_of_points&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Factor: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-ko&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markevery&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;span class="n"&gt;plot_static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="times-table-2-100" class="narrow b-lazy" data-src="/blog/images/times_tables/times-tables-2-100.png" src="https://elc.github.io/blog/images/times_tables/times-tables-2-100-thumbnail.png" width="900"&gt;&lt;/p&gt;
&lt;h2 id="parametric-version"&gt;&lt;a class="toclink" href="#parametric-version"&gt;Parametric Version&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;One method to update the factor and points variables is to manually change them
and re-execute the cell or function. However, Jupyter offers support for
interaction, allowing for a more user-friendly approach via Sliders, a built-in
user interface of IPython. The function plot_parametric serves the same purpose
as plot_static, with the addition of a call to plt.show() at the end to display
the image. While the image is still static, the user can adjust the variables by
moving the sliders.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;plot_parametric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;points_around_circle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_line_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gca&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;off&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-ko&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markevery&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="n"&gt;factors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;34&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;49&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;51&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;66&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;73&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;76&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;79&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;86&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;91&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Try these Factors with different number of points:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;factors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;plot_parametric&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="iframe-container" style="padding-top: 101%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/times-tables/times-table-parametric-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="animate-construction-line-by-line"&gt;&lt;a class="toclink" href="#animate-construction-line-by-line"&gt;Animate Construction Line by Line&lt;/a&gt;&lt;/h2&gt;
&lt;video class="b-lazy" autoplay loop width=900&gt;
    &lt;source data-src="/blog/images/times_tables/line_by_line.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;In the next step, the focus shifts to animations. In this particular animation,
the factor and the number of points remain constant while the lines change. This
animation replicates the act of drawing these times tables by hand and provides
a deeper understanding of the sequence in which the lines are plotted, instead
of simply presenting them all together.&lt;/p&gt;
&lt;p&gt;In Matplotlib, animations are constructed using the animate function, which
returns the objects to be displayed in each frame. As a result, two functions
need to be defined in this and the following animations. The first is for the
animate API of Matplotlib and the second is to be integrated into the interact
function of IPython. In this particular case, the function line_by_line takes a
given &lt;code&gt;factor&lt;/code&gt;, a specified number of &lt;code&gt;max_points&lt;/code&gt;, and an &lt;code&gt;interval&lt;/code&gt;. The first
two parameters are already familiar from previous functions, while interval
represents the delay between frames in milliseconds. This delay is directly
related to the animation's frames per second (FPS), which is calculated as FPS =
1000 / delay.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;animate_line_by_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;npt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NDArray&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Axes&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Line2D&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;start_point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_point&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;
    &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Line2D&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start_point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end_point&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;line_by_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FuncAnimation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;points_around_circle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_lines_from_points&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;fig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gca&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;off&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Factor: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Interval: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Points: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-ko&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markevery&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FuncAnimation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;animate_line_by_line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_points&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;blit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;fargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;anim&lt;/span&gt;


&lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;line_by_line&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="iframe-container" style="padding-top: 101%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/times-tables/times-table-line-by-line-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="animate-construction-point-by-point"&gt;&lt;a class="toclink" href="#animate-construction-point-by-point"&gt;Animate Construction Point by Point&lt;/a&gt;&lt;/h2&gt;
&lt;video class="b-lazy" autoplay loop width=900&gt;
    &lt;source data-src="/blog/images/times_tables/point_by_point.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;The next animation focuses on the process of how the figure becomes clearer as
the number of points increases. The factor is fixed, and all lines are plotted
at once, but with each frame, the number of points increases incrementally from
0 to a specified maximum number of &lt;code&gt;max_points&lt;/code&gt;. This perspective provides a
different view on the relationship between the number of points and the clarity
of the figure.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;animate_point_by_point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Axes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Line2D&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;points_around_circle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_line_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cla&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;off&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Interval: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Points: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Factor: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-ko&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markevery&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;point_by_point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FuncAnimation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gca&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FuncAnimation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;animate_point_by_point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;blit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;fargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;anim&lt;/span&gt;


&lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;point_by_point&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;75&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="iframe-container" style="padding-top: 101%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/times-tables/times-table-point-by-point-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="animate-construction-factor-by-factor"&gt;&lt;a class="toclink" href="#animate-construction-factor-by-factor"&gt;Animate Construction Factor by Factor&lt;/a&gt;&lt;/h2&gt;
&lt;video class="b-lazy" autoplay loop width=900&gt;
    &lt;source data-src="/blog/images/times_tables/factor_by_factor.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;The animation displays the effect of incrementing the factor, with the number of
points fixed and all lines plotted at once. To enhance the visual impact, the
factor is increased in increments of 0.1 instead of 1. This results in a
smoother animation. This version is monochromatic, with all lines appearing in
the same color.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;animate_factor_by_factor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Axes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Line2D&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;points_around_circle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_line_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cla&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;off&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_ylim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xlim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Interval: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Points: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Factor: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-ko&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markevery&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;factor_by_factor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FuncAnimation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gca&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;frames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FuncAnimation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;animate_factor_by_factor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;blit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;fargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;anim&lt;/span&gt;


&lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;factor_by_factor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="iframe-container" style="padding-top: 101%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/times-tables/times-table-factor-by-factor-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="animate-construction-factor-by-factor-with-color"&gt;&lt;a class="toclink" href="#animate-construction-factor-by-factor-with-color"&gt;Animate Construction Factor by Factor with Color&lt;/a&gt;&lt;/h2&gt;
&lt;video class="b-lazy" autoplay loop width=900&gt;
    &lt;source data-src="/blog/images/times_tables/factor_by_factor_colored.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;p&gt;The final animation is similar to the previous one, with the difference being
the addition of color. To achieve this, the function
&lt;code&gt;animate_factor_by_factor_colored&lt;/code&gt; is passed an additional parameter, &lt;code&gt;frames&lt;/code&gt;,
which specifies the total number of frames. The HSV color system is utilized,
with fixed saturation and value, while the hue changes from 0 to 1 as the
current frame (&lt;code&gt;i&lt;/code&gt;) is divided by the total number of frames (&lt;code&gt;frames&lt;/code&gt;),
resulting in a range from 0 to 1.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;animate_factor_by_factor_colored&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Axes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Line2D&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;points_around_circle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;generate_line_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cla&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;off&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Interval: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Points: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Factor: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;-ko&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;markevery&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;factor_by_factor_colored&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FuncAnimation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gca&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;frames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FuncAnimation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;animate_factor_by_factor_colored&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;blit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;fargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;anim&lt;/span&gt;


&lt;span class="n"&gt;interact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;factor_by_factor_colored&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;FloatSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;max_points&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IntSlider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Layout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;99%&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="iframe-container" style="padding-top: 101%"&gt;
    &lt;iframe class="b-lazy" data-src="https://elc.github.io/blog/iframes/times-tables/times-table-factor-by-factor-colored-iframe.html"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="export"&gt;&lt;a class="toclink" href="#export"&gt;Export&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The generated animations can be exported as mp4 files by calling the appropriate
function, storing the result in a variable and using the following code snippet.
The function &lt;code&gt;specific_function&lt;/code&gt; should be replaced with the desired animation,
such as &lt;code&gt;factor_by_factor_colored&lt;/code&gt; or &lt;code&gt;animate_point_by_point&lt;/code&gt;, and the
corresponding parameters should be included.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;specific_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;my_animation.mp4&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;Writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ffmpeg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;anim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Data Visualization"></category><category term="Data Visualization"></category><category term="Matplotlib"></category><category term="Python"></category><category term="Animation"></category></entry><entry><title>Pascal Triangle and Genetic Algorithm - A Visualization</title><link href="https://elc.github.io/posts/pascal-triangle-vs-genetic-algorithm" rel="alternate"></link><published>2019-01-21T00:00:00-03:00</published><updated>2019-01-21T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2019-01-21:/posts/pascal-triangle-vs-genetic-algorithm</id><summary type="html">

&lt;p&gt;Inspired by a Wikipedia article, I replicate a way to visualize the Pascal Triangle and used the same approach in Genetic Algorithms&lt;/p&gt;


&lt;p&gt;Once I came accross this &lt;a href="https://en.wikipedia.org/wiki/Pascal%27s_triangle" target="_blank"&gt;wikipedia article about Pascal Triangle&lt;/a&gt;, there you can find the following animation:&lt;/p&gt;
&lt;p&gt;&lt;img alt="pascal_triangle_animation" class="narrow" src="https://upload.wikimedia.org/wikipedia/commons/6/66/Pascal%27s_Triangle_animated_binary_rows.gif" width="576"&gt;&lt;/p&gt;
&lt;p&gt;I found it interesting to replicate this very animation in Python …&lt;/p&gt;</summary><content type="html">

&lt;p&gt;Inspired by a Wikipedia article, I replicate a way to visualize the Pascal Triangle and used the same approach in Genetic Algorithms&lt;/p&gt;


&lt;p&gt;Once I came accross this &lt;a href="https://en.wikipedia.org/wiki/Pascal%27s_triangle" target="_blank"&gt;wikipedia article about Pascal Triangle&lt;/a&gt;, there you can find the following animation:&lt;/p&gt;
&lt;p&gt;&lt;img alt="pascal_triangle_animation" class="narrow" src="https://upload.wikimedia.org/wikipedia/commons/6/66/Pascal%27s_Triangle_animated_binary_rows.gif" width="576"&gt;&lt;/p&gt;
&lt;p&gt;I found it interesting to replicate this very animation in Python, just as a challenge and maybe later I would find a useful application for it. At &lt;a href="#notebook"&gt;&lt;strong&gt;the end&lt;/strong&gt;&lt;/a&gt; I will add a link to the jupyter notebook so you can experiment your own variants. If you want, you can jump directly to the &lt;a href="#application-in-genetic-algorithms"&gt;&lt;strong&gt;genetic algorithm application&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, there are some tools we need to install:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Jupyter (Optional): Notebook Interface&lt;/li&gt;
&lt;li&gt;Numpy: For array manipulation&lt;/li&gt;
&lt;li&gt;Matplotlib: For visualization and animation&lt;/li&gt;
&lt;li&gt;ffmpeg (Optional): For exporting the animation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once everything is installed, we need to understand what is necessary, I decided to split the code in 5 parts, although it can be a single file script. The final result is the following:&lt;/p&gt;
&lt;video class="b-lazy" autoplay loop width=900&gt;
    &lt;source data-src="/blog/images/pascal_triangle/pascal_triangle.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;h3 id="initialization"&gt;&lt;a class="toclink" href="#initialization"&gt;Initialization&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, import everything needed, this should be the first cell in the notebook or be placed at the top of the script&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;plt&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;matplotlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;IPython.display&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HTML&lt;/span&gt; &lt;span class="c1"&gt;# Only required for Jupyter&lt;/span&gt;

&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;matplotlib&lt;/span&gt; &lt;span class="n"&gt;inline&lt;/span&gt; &lt;span class="c1"&gt;# Only required for Jupyter&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="pascal-triangle"&gt;&lt;a class="toclink" href="#pascal-triangle"&gt;Pascal Triangle&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Secondly, define the proper functions to create a Pascal triangle, since for every frame only the last row is represented, a separate function that returns only that row is generated, to avoid unnecessary array manipulation. Additionally since many frames could be asked, it's important to cache the intermediate results since every pascal triangle is build based on the previous one, for this purpose a technique named memoization is used and this is the reason of why pascal_triangle is a recursive function.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;memoize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;memo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;helper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;memo&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;helper&lt;/span&gt;

&lt;span class="nd"&gt;@memoize&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pascal_triangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])]&lt;/span&gt;
    &lt;span class="n"&gt;prev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pascal_triangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;middle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pascal_triangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;middle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;dtype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ulonglong&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

&lt;span class="nd"&gt;@memoize&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pascal_last_row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pascal_triangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="animation-function"&gt;&lt;a class="toclink" href="#animation-function"&gt;Animation Function&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Thirdly, Matplotlib asks a function to animate which will generate each frame. For this purpose each frame is generated, adding extra white space to the sides when needed and returning a blank image for the 0 frame&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;im&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt; &lt;span class="n"&gt;cmap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Greys&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aspect&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;equal&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;animated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;im&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pascal_last_row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;extra_space&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;extra_space&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;extra_space&lt;/span&gt;

    &lt;span class="n"&gt;real_width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;real_width&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;real_width&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="n"&gt;binary_elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zfill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="n"&gt;binary_elements&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;im&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;imshow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transpose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;binary_elements&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;cmap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Greys&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;aspect&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;equal&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;real_width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;animated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;im&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="animation-video"&gt;&lt;a class="toclink" href="#animation-video"&gt;Animation Video&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Finally, the main part of the script is where the crucial variables are defined such as the number of frames and the width of the window.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;frames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;span class="n"&gt;last_row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pascal_last_row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;bin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_row&lt;/span&gt;&lt;span class="p"&gt;))[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:])&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;aspect_ratio&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;

&lt;span class="n"&gt;frame_width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;

&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;figsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frame_width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frame_width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;aspect_ratio&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subplots_adjust&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bottom&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.01&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_xticks&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt; 
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_yticks&lt;/span&gt;&lt;span class="p"&gt;([])&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;frames&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

&lt;span class="n"&gt;anim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FuncAnimation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;animate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fargs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Avoid extra picture&lt;/span&gt;

&lt;span class="n"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;anim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_html5_video&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;# Only required for Jupyter, replace this line with plt.show() for scripts&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="export"&gt;&lt;a class="toclink" href="#export"&gt;Export&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As a bonus, if the animation is needed as a separate file, ffmpeg can be used through Matplotlib to generate the corresponding mp4 file&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;animation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;writers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ffmpeg&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;artist&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Me&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;bitrate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1800&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;anim&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;im.mp4&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="final-result"&gt;&lt;a class="toclink" href="#final-result"&gt;Final Result&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As seen at the beginning the previous code resulted in the following animation:&lt;/p&gt;
&lt;video class="b-lazy" autoplay loop width=900&gt;
    &lt;source data-src="/blog/images/pascal_triangle/pascal_triangle.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;h2 id="notebook"&gt;&lt;a class="toclink" href="#notebook"&gt;Notebook&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Everything showed above can be executed without installing anything just by using Binder, &lt;a href="https://elc.github.io/link/pascal_triangle_binder" target="_blank"&gt;&lt;strong&gt;open the gist online&lt;/strong&gt;&lt;/a&gt; and experiment yourself.&lt;/p&gt;
&lt;h2 id="application-in-genetic-algorithms"&gt;&lt;a class="toclink" href="#application-in-genetic-algorithms"&gt;Application in Genetic Algorithms&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When I started this visualization challenge, I had no application in mind but then I realized the same approach could be used for visualizing the genotype of a population of chromosomes in a traditional genetic algorithm. Each colum would represent a chromosome instead of a number each row a particular gene for each chromosome, being black if the gene is 1 and white if it is 0. This approach asumes a binary genotype configuration. Then another possible improvement is to sort them by fitness, the ones with the highest fitness on the left and the ones with the lowest on the right. Sorting them could help understanding patterns in the genotype that might not be obvious in the phenotype.&lt;/p&gt;
&lt;p&gt;This is the result of finding the maximum of a function with elitism and high mutation. Each frame represents a population the next frame represents the childs of the previous one. The source code that generates this animation can be found in my &lt;a href="https://elc.github.io/link/genetic_algorithm_repo" target="_blank"&gt;&lt;strong&gt;personal github repository&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;video class="b-lazy" autoplay loop width=900&gt;
    &lt;source data-src="/blog/images/pascal_triangle/genetic_algorithm.mp4" type="video/mp4"&gt;
&lt;/video&gt;</content><category term="Data Visualization"></category><category term="Data Visualization"></category><category term="Python"></category><category term="Matplotlib"></category><category term="Animation"></category></entry><entry><title>Juegos Bíblicos para Jóvenes y Adolescentes</title><link href="https://elc.github.io/posts/juegos-biblicos/es" rel="alternate"></link><published>2018-12-28T00:00:00-03:00</published><updated>2018-12-28T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2018-12-28:/posts/juegos-biblicos/es</id><summary type="html">

&lt;p&gt;Compilado de juegos bíblicos listos para imprimir. Pensados y adaptados para jóvenes y adolescentes que buscan conocer más a Dios.&lt;/p&gt;


&lt;p&gt;EDICIÓN 2020.18.15: Ya está disponible la &lt;a href="/link/tabu-biblico-web"&gt;app web para el Tabú Bíblico&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;En el pasado yo siempre tuve una mirada despectiva de los juegos, pensé que eran innecesarios …&lt;/p&gt;</summary><content type="html">

&lt;p&gt;Compilado de juegos bíblicos listos para imprimir. Pensados y adaptados para jóvenes y adolescentes que buscan conocer más a Dios.&lt;/p&gt;


&lt;p&gt;EDICIÓN 2020.18.15: Ya está disponible la &lt;a href="/link/tabu-biblico-web"&gt;app web para el Tabú Bíblico&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;En el pasado yo siempre tuve una mirada despectiva de los juegos, pensé que eran innecesarios e infantiles pero fue el Señor que me sorprendió dandome la habilidad para diseñarlos y encontrarme con que resultaron ser de suma utilidad, tanto en una reunión de jóvenes como de adolescentes.&lt;/p&gt;
&lt;p&gt;En este artículo voy a dejar todos los juegos que vaya diseñando, la idea es tener un lugar centralizado donde las personas puedan referenciar y también proveer plantillas para que puedan ser adaptados si hiciera falta. Cada juego va a tener una imagen que muestra como es, las instrucciones, un enlace a una versión en PDF lista para imprimir y recortar y un enlace a una versión de Google Docs lista para descargar y adaptar.&lt;/p&gt;
&lt;p&gt;Adicionalmente, toda crítica, sugerencia y comentario es bien recibido, pueden dejarlo expresado en los comentarios al final de este artículo.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;También te puede interesar:&lt;/strong&gt; si participás en una actividad donde se utilizan presentationes en Power Point para pasar las letras de las canciones (campamentos, reunión de jóvenes, etc.), puede interesarte esta &lt;strong&gt;&lt;a href="https://elc.github.io/lyrics-presentation/" target="_blank"&gt;aplicación online&lt;/a&gt;&lt;/strong&gt; para generar las presentaciones automáticamente.&lt;/p&gt;
&lt;h2 id="indice"&gt;&lt;a class="toclink" href="#indice"&gt;Índice&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#tabu-biblico"&gt;Tabú Bíblico&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#trivia-adolescente"&gt;Trivia Adolescente&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#conoce-la-historia"&gt;Conocé la historia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#espadeo-biblico-version-modificada"&gt;Espadeo Bíblico - Versión Modificada&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#memo-paralelo"&gt;Memo Paralelo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#arma-la-historia"&gt;Armá la Historia&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tabu-biblico"&gt;&lt;a class="toclink" href="#tabu-biblico"&gt;Tabú Bíblico&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="#indice"&gt;Volver al Índice&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/juegos-biblicos/tabu_biblico_01.jpg"&gt;&lt;img alt="conoce_la_historia" class="narrow b-lazy" data-src="/blog/images/juegos-biblicos/tabu_biblico_01.jpg" src="https://elc.github.io/blog/images/juegos-biblicos/tabu_biblico_01-thumbnail.jpg" width="665"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Se arman equipos y se juega por turnos, en el turno de un equipo, se designa una persona, a esta persona se le entregan una serie de tarjetas, las tarjetas van a tener una palabra principal y una serie de palabras secundarias. El objetivo es que la persona designada pueda hacer que su equipo adivine cual es la palabra principal sin utilizar las palabras secundarias, ni sus familias de palabras, tampoco puede usar mímica ni decir cuántas letras tiene la palabra principal o usar referencias fonéticas.&lt;/p&gt;
&lt;p&gt;La persona designada puede saltear la carta si lo cree conveniente. Por cada tarjeta adivinada en el tiempo fijado, el equipo gana un punto y por cada tarjeta salteada o penalizada el equipo pierde un punto. Luego de una cierta cantidad de rondas prefijada el equipo con más puntos gana.&lt;/p&gt;
&lt;p&gt;La tarjetas tienen distintas dificultades y deben estar mezcladas previamente, una vez que la tarjeta fue adivinada se separa, las tarjetas salteadas o penalizadas siguen en juego.&lt;/p&gt;
&lt;p&gt;Descargar el documento editable (Ver &lt;a href="#instrucciones-para-la-version-editable"&gt;Instrucciones&lt;/a&gt;) &lt;a href="/link/tabu-biblico" target="_blank"&gt;&lt;img alt="Download DOC" class="narrow svg-button" src="https://elc.github.io/theme/images/DOC.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Descargar el PDF listo para imprimir &lt;a href="/link/tabu-biblico-pdf" target="_blank"&gt;&lt;img alt="Downlaod PDF" class="narrow svg-button" src="https://elc.github.io/theme/images/PDF.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Ahora también disponible como app web para celulares y PCs: Disponible online &lt;a href="/link/tabu-biblico-web"&gt;aquí&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="trivia-adolescente"&gt;&lt;a class="toclink" href="#trivia-adolescente"&gt;Trivia Adolescente&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="#indice"&gt;Volver al Índice&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/juegos-biblicos/trivia_adolescentes_01.jpg"&gt;&lt;img alt="conoce_la_historia" class="narrow b-lazy" data-src="/blog/images/juegos-biblicos/trivia_adolescentes_01.jpg" src="https://elc.github.io/blog/images/juegos-biblicos/trivia_adolescentes_01-thumbnail.jpg" width="657"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;El juego consiste en responder preguntas - para ganar - se deben responder al menos una pregunta correctamente de cada categoría. Dentro de cada categoría hay preguntas de distintas dificultades.&lt;/p&gt;
&lt;p&gt;Las categorías son:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Historia&lt;/li&gt;
&lt;li&gt;Geografía&lt;/li&gt;
&lt;li&gt;Arte y Entretenimiento&lt;/li&gt;
&lt;li&gt;Ciencia&lt;/li&gt;
&lt;li&gt;Deportes&lt;/li&gt;
&lt;li&gt;Biblia&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Descargar el documento editable (Ver &lt;a href="#instrucciones-para-la-version-editable"&gt;Instrucciones&lt;/a&gt;) &lt;a href="/link/trivia-adolescente" target="_blank"&gt;&lt;img alt="Download DOC" class="narrow svg-button" src="https://elc.github.io/theme/images/DOC.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Descargar el PDF listo para imprimir &lt;a href="/link/trivia-adolescente-pdf" target="_blank"&gt;&lt;img alt="Downlaod PDF" class="narrow svg-button" src="https://elc.github.io/theme/images/PDF.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="conoce-la-historia"&gt;&lt;a class="toclink" href="#conoce-la-historia"&gt;Conocé la historia&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="#indice"&gt;Volver al Índice&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/juegos-biblicos/conoce_la_historia_01.jpg"&gt;&lt;img alt="conoce_la_historia" class="b-lazy" data-src="/blog/images/juegos-biblicos/conoce_la_historia_01.jpg" src="https://elc.github.io/blog/images/juegos-biblicos/conoce_la_historia_01-thumbnail.jpg" width="1344"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A cada jugador se le coloca una tarjeta en la espalda, cada tarjeta contiene una serie de oraciones que están vinculadas a un personaje bíblico, pueden ser eventos, lugares, pasajes o cualquier otro dato relacionado.&lt;/p&gt;
&lt;p&gt;Los jugadores deberán preguntarles a los demás que dice su tarjeta, sin embargo sólo le dirán un dato, y para darle ese dato debe mencionar correctamente y en orden todos los anteriores. Es decir, el primer dato se lo dirá sin preguntar nada, para darle el segundo debe decir el primero, para darle el tercero debe decir el primero y el segundo.&lt;/p&gt;
&lt;p&gt;El primer jugador que se acerque al organizador y pueda decir todos los datos correctamente y en orden será el ganador.&lt;/p&gt;
&lt;p&gt;Descargar el documento editable (Ver &lt;a href="#instrucciones-para-la-version-editable"&gt;Instrucciones&lt;/a&gt;) &lt;a href="/link/conoce-historia" target="_blank"&gt;&lt;img alt="Download DOC" class="narrow svg-button" src="https://elc.github.io/theme/images/DOC.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Descargar el PDF listo para imprimir &lt;a href="/link/conoce-historia-pdf" target="_blank"&gt;&lt;img alt="Downlaod PDF" class="narrow svg-button" src="https://elc.github.io/theme/images/PDF.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="espadeo-biblico-version-modificada"&gt;&lt;a class="toclink" href="#espadeo-biblico-version-modificada"&gt;Espadeo Bíblico - Versión Modificada&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="#indice"&gt;Volver al Índice&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/juegos-biblicos/espadeo_01.jpg"&gt;&lt;img alt="conoce_la_historia" class="narrow b-lazy" data-src="/blog/images/juegos-biblicos/espadeo_01.jpg" src="https://elc.github.io/blog/images/juegos-biblicos/espadeo_01-thumbnail.jpg" width="669"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/juegos-biblicos/espadeo_02.jpg"&gt;&lt;img alt="conoce_la_historia" class="narrow b-lazy" data-src="/blog/images/juegos-biblicos/espadeo_02.jpg" src="https://elc.github.io/blog/images/juegos-biblicos/espadeo_02-thumbnail.jpg" width="748"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/juegos-biblicos/espadeo_03.jpg"&gt;&lt;img alt="conoce_la_historia" class="narrow b-lazy" data-src="/blog/images/juegos-biblicos/espadeo_03.jpg" src="https://elc.github.io/blog/images/juegos-biblicos/espadeo_03-thumbnail.jpg" width="739"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Este es un juego con 3 modalidales, el organizador puede alternar entre ellas o escoger la que más se adapte a sus necesidades.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modalidad clásica: Se lee una pequeña introducción y luego la cita de un versículo y los equipos deben buscarlo, el que lo encuentre debe comenzar a leerlo inmediatamente, si es el versículo correcto, gana.&lt;/li&gt;
&lt;li&gt;Modalidad Completar el versículo: Se lee una pequeña introducción y luego un versículo en forma incompleta, los equipos tienen la posibilidad de completarlo si lo saben de memoria, se dan unos segundos para esto. En caso de que ninguno de los equipos haya respondido, se dice cuál es la cita y se procede con la modalidad clásica, el equipo que complete el versículo antes es el que gana.&lt;/li&gt;
&lt;li&gt;Modalidad Preguntas con Opciones: Se hace una pregunta y se dan tres citas como posibles soluciones, en todos los casos hay sólo una respuesta correcta. Cada equipo debe buscar las opciones y comenzar a leer el versículo que corresponda. El primer equipo que lea el versículo correspondiente a la pregunta es el ganador. Los equipos pueden decir la cita y el versículo de memoria si lo saben.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Descargar el documento editable (Ver &lt;a href="#instrucciones-para-la-version-editable"&gt;Instrucciones&lt;/a&gt;) &lt;a href="/link/espadeo-biblico" target="_blank"&gt;&lt;img alt="Download DOC" class="narrow svg-button" src="https://elc.github.io/theme/images/DOC.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Descargar el PDF listo para imprimir &lt;a href="/link/espadeo-biblico-pdf" target="_blank"&gt;&lt;img alt="Downlaod PDF" class="narrow svg-button" src="https://elc.github.io/theme/images/PDF.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="memo-paralelo"&gt;&lt;a class="toclink" href="#memo-paralelo"&gt;Memo Paralelo&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="#indice"&gt;Volver al Índice&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/juegos-biblicos/memo_paralelo_01.jpg"&gt;&lt;img alt="conoce_la_historia" class="b-lazy" data-src="/blog/images/juegos-biblicos/memo_paralelo_01.jpg" src="https://elc.github.io/blog/images/juegos-biblicos/memo_paralelo_01-thumbnail.jpg" width="1092"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/juegos-biblicos/memo_paralelo_02.jpg"&gt;&lt;img alt="conoce_la_historia" class="b-lazy" data-src="/blog/images/juegos-biblicos/memo_paralelo_02.jpg" src="https://elc.github.io/blog/images/juegos-biblicos/memo_paralelo_02-thumbnail.jpg" width="1077"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Se arman equipos y a cada equipo se le da una serie de tarjetas, cada equipo coloca sus tarjetas boca abajo. Una persona de cada equipo será la encargada de dar vuelta las tarjetas, cada tarjeta contiene una cita a un pasaje bíblico o un pasaje escrito. El objetivo del juego es agrupar las tarjetas de a pares según el tema que traten. &lt;/p&gt;
&lt;p&gt;La persona designada sólo podrá voltear dos tarjetas a la vez, si desea voltear una tercera deberá colocar boca abajo alguna de las otras dos antes. Los miembros del equipo deben ayudar buscando los pasajes e identificar cuales son los que están relacionados.&lt;/p&gt;
&lt;p&gt;Es importante asegurarse que antes de darles las tarjetas a los equipos cada tarjeta tenga su par. El organizador tendrá una lista de todos los pares para poder validar si los equipos resolvieron el juego correctamente, el equipo que haya encontrado más pares en el tiempo fijado será el ganador.&lt;/p&gt;
&lt;p&gt;Descargar el documento editable (Ver &lt;a href="#instrucciones-para-la-version-editable"&gt;Instrucciones&lt;/a&gt;) &lt;a href="/link/memo-paralelo" target="_blank"&gt;&lt;img alt="Download DOC" class="narrow svg-button" src="https://elc.github.io/theme/images/DOC.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Descargar el PDF listo para imprimir &lt;a href="/link/memo-paralelo-pdf" target="_blank"&gt;&lt;img alt="Downlaod PDF" class="narrow svg-button" src="https://elc.github.io/theme/images/PDF.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="arma-la-historia"&gt;&lt;a class="toclink" href="#arma-la-historia"&gt;Armá la Historia&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="#indice"&gt;Volver al Índice&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/juegos-biblicos/arma_la_historia_01.jpg"&gt;&lt;img alt="conoce_la_historia" class="b-lazy" data-src="/blog/images/juegos-biblicos/arma_la_historia_01.jpg" src="https://elc.github.io/blog/images/juegos-biblicos/arma_la_historia_01-thumbnail.jpg" width="1090"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A cada equipo se le da una serie de tarjetas, algunas contienen pasajes y otras contienen eventos o historias. Cada equipo deberá asociar cada tarjeta de evento con una de un pasaje y luego ordenarlas para formar la historia bíblica.&lt;/p&gt;
&lt;p&gt;Al principio a cada equipo se le da una historia fácil y cada vez que completen una historia se le da una de mayor dificultad, sólo se considerará correcta si todas las tarjetas están en la posición adecuada. El organizador deberá decir que es incorrecta sin mencionar dónde está el error. En caso de empate el punto va para el equipo que más tarjetas correctas tenga en la historia en curso.&lt;/p&gt;
&lt;p&gt;Descargar el documento editable (Ver &lt;a href="#instrucciones-para-la-version-editable"&gt;Instrucciones&lt;/a&gt;) &lt;a href="/link/arma-historia" target="_blank"&gt;&lt;img alt="Download DOC" class="narrow svg-button" src="https://elc.github.io/theme/images/DOC.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Descargar el PDF listo para imprimir &lt;a href="/link/arma-historia-pdf" target="_blank"&gt;&lt;img alt="Downlaod PDF" class="narrow svg-button" src="https://elc.github.io/theme/images/PDF.svg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="instrucciones-para-la-version-editable"&gt;&lt;a class="toclink" href="#instrucciones-para-la-version-editable"&gt;Instrucciones para la versión editable&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cada juego tiene se puede acceder de dos maneras, en PDF o en formato de Google Docs (Similar al Microsoft Word). Al final de la descripción de cada juego habrá dos botones para cada forma respectivamente.&lt;/p&gt;
&lt;p&gt;La versión en PDF no es editable pero es la más fácil de imprimir (no se cambia el formato al imprimir), en caso de requerir ediciones, éstas pueden hacerse libremente en el formato de Google Docs o Microsoft Word.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Si decidiste modificar alguno de los juegos, me encantaría que pudieras compartir las modificaciones mandándome un email a &lt;/em&gt;&lt;em&gt;castanoezequielleonardo@gmail.com&lt;/em&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Para utilizar la versión de Google Docs se debe iniciar primero en la cuenta de Google (en su correo de @gmail) y luego tendrá la posibilidad de "Hacer una copia" esa copia es completamente suya y allí podrá hacer todas las modificaciones necesarias.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/juegos-biblicos/descargar_tutorial_01.png"&gt;&lt;img alt="Hacer Copia Google Docs" class="narrow b-lazy" data-src="/blog/images/juegos-biblicos/descargar_tutorial_01.png" src="https://elc.github.io/blog/images/juegos-biblicos/descargar_tutorial_01-thumbnail.png" width="669"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Por otro lado, en caso de preferir el entorno de Microsoft Word, basta con hacer click en "Descargar" y luego seleccionar el formato preferido, el de Microsoft Word es el "docx".&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/juegos-biblicos/descargar_tutorial_02.png"&gt;&lt;img alt="Descargar Docx" class="narrow b-lazy" data-src="/blog/images/juegos-biblicos/descargar_tutorial_02.png" src="https://elc.github.io/blog/images/juegos-biblicos/descargar_tutorial_02-thumbnail.png" width="669"&gt;&lt;/a&gt;&lt;/p&gt;</content><category term="Christianity"></category><category term="Christian"></category><category term="Games"></category><category term="Bible"></category></entry><entry><title>Step by Step Fractals with Python</title><link href="https://elc.github.io/posts/plotting-fractals-step-by-step-with-python" rel="alternate"></link><published>2018-11-04T00:00:00-03:00</published><updated>2018-11-04T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2018-11-04:/posts/plotting-fractals-step-by-step-with-python</id><summary type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/fractals/factals_headerimage.png"&gt;&lt;img alt="Fractals Header Image" class="b-lazy" data-src="/blog/images/fractals/factals_headerimage.png" src="https://elc.github.io/blog/images/fractals/factals_headerimage-thumbnail.png" width="1920"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Fractals are awesome, they are built with very complex pattern and they allow you to zoom in forever! In this post we will see how easily it is to plot several kinds of fractals using a tool called L-Systems and the Python Turtle module for the step to step plotting …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/fractals/factals_headerimage.png"&gt;&lt;img alt="Fractals Header Image" class="b-lazy" data-src="/blog/images/fractals/factals_headerimage.png" src="https://elc.github.io/blog/images/fractals/factals_headerimage-thumbnail.png" width="1920"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Fractals are awesome, they are built with very complex pattern and they allow you to zoom in forever! In this post we will see how easily it is to plot several kinds of fractals using a tool called L-Systems and the Python Turtle module for the step to step plotting.&lt;/p&gt;


&lt;p&gt;In this post I'm not going to dive into too many technical details but instead I'll present a little introduction, a lot of animated examples and at the end, the code to generate your own. If you want skip the theory and see the animations, jump directly to the &lt;a href="#animated-examples"&gt;animated examples&lt;/a&gt;, if you want to see the code instead, &lt;a href="#code"&gt;jump directly to that section&lt;/a&gt;. Additionally, there will be some resources for both code and math background if you want to explore &lt;a href="#additional-resources"&gt;at the end&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="whats-a-fractal"&gt;&lt;a class="toclink" href="#whats-a-fractal"&gt;What's a Fractal?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First lets give a "non-strict" definition of what a fractal is, it is basically a geometric figure which shows the same characteristics no matter how much you zoom in.&lt;/p&gt;
&lt;p&gt;It isn't quite correct but for those who wanted to know the exact definition here it is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A fractal is an object or quantity that displays self-similarity, in a somewhat technical sense, on all scales. The object need not exhibit exactly the same structure at all scales, but the same "type" of structures must appear on all scales. A plot of the quantity on a log-log graph versus scale then gives a straight line, whose slope is said to be the fractal dimension. - &lt;a href="http://mathworld.wolfram.com/Fractal.html" target="_blank"&gt;Math World&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="how-can-we-draw-fractals-with-python"&gt;&lt;a class="toclink" href="#how-can-we-draw-fractals-with-python"&gt;How can we draw Fractals with Python?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Fractals are typically hard to draw, because there is a concept which is deeply tight in them, recursion. When we talk about graphics and plotting we usually talk about pixels or vectors, but there is always a limit, fractals by definition are infinitely recursive. So when we want to plot one we should stop at some point, that's why we talk about "iterations". At each iteration the fractal becomes more and more complex, but at some point it is impossible to distinguish between to successive iterations (this happens when changes occur at individual pixel levels), so it is quite reasonable to stop there, sometimes it is quite clear what the shape is and we can stop even earlier.&lt;/p&gt;
&lt;p&gt;A two examples for this are the Quadratic Koch Island, which with 3 iterations has a clear structure and in the other hand the Dragon Curve which has a clear structure with 8 iterations. How many iterations are needed depends highly on the specific fractal we are working with.&lt;/p&gt;
&lt;p&gt;Certainly there are lots of plotting libraries in Python, being Matplotlib the most popular but they are usually design to plot statistical data and well known plots. Matplotlib in particular has some low level constructs that allow us to build fractals but this time we will be focusing in a usually forget module in the standard library, the Turtle Module.&lt;/p&gt;
&lt;h3 id="turtle-module"&gt;&lt;a class="toclink" href="#turtle-module"&gt;Turtle Module&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;According to &lt;a href="https://docs.python.org/3.6/library/turtle.html" target="_blank"&gt;Python docs&lt;/a&gt;: "Turtle graphics is a popular way for introducing programming to kids. It was part of the original Logo programming language developed by Wally Feurzig and Seymour Papert in 1966."&lt;/p&gt;
&lt;p&gt;The key here is that turtle recognizes basically 3 commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Move Forwards&lt;/li&gt;
&lt;li&gt;Turn Left by angle&lt;/li&gt;
&lt;li&gt;Turn Right by angle&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Note: THe standard library provided other commands but here we are going to just those 3.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Additionally we have the option to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Disable writing&lt;/li&gt;
&lt;li&gt;Enable writing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This characteristics seems too simple for plotting such complex graphics as fractals but we will use another tool that uses just this little set of instructions, I'm talking about L-Systems.&lt;/p&gt;
&lt;h3 id="l-systems"&gt;&lt;a class="toclink" href="#l-systems"&gt;L-Systems&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An L-System is a way of representing recursive structures (such as fractals) as a string of characters, this is done by rewriting the string over and over. Again, the formal definition is the following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A Lindenmayer system, also known as an L-system, is a string rewriting system that can be used to generate fractals with dimension between 1 and 2. - &lt;a href="http://mathworld.wolfram.com/LindenmayerSystem.html" target="_blank"&gt;Math World&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once we understand what an L-System is we can produce recursive structures, but before we are able to do that we need to understand what are the pieces we need. Every L-System has:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An alphabet: The set of symbols the L-System is going to use.&lt;/li&gt;
&lt;li&gt;An axiom: The initial string for the generation.&lt;/li&gt;
&lt;li&gt;A set of production rules: These rules tells how each symbol should be replaced in the following iteration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Note for computer science fans: If you ever dived into Computer Science this might sound familiar, it is actually since this is very similar to the definition of a Formal Grammar, the key difference is that in each iteration, as opposed to grammars, as many rules as possible are applied instead of just one. So L-Systems are a subset of Context-Free Grammars.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Since we are going to use Turtle to plot and L-Systems to represent what we want to plot we need to create a relationship between them.&lt;/p&gt;
&lt;p&gt;Since the only commands we have in Turtle are the mentioned above we will assign each a symbol which will represent the alphabet&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;F: Move Forwards&lt;/li&gt;
&lt;li&gt;+: Turn Right&lt;/li&gt;
&lt;li&gt;-: Turn Left&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In order to make this work, each fractal should also provide an angle, which will be the angle the turtle will turn either right or left, for simplicity reasons only one angle should be provided and the L-System should be written taking that into consideration.&lt;/p&gt;
&lt;p&gt;The axiom and the production rules will depend on the fractal only, but the fractal should be written in a way that can be represented by these only three symbols. This introduces a limitation, we will be able to produce only one-line fractals, so some such as the Cantor Set won't be able to be produced this way, this is only a simplification, since we can introduce two other commands to move forwards without writing and analogously for the backwards movement, but to keep things simple we will keep that simplification.&lt;/p&gt;
&lt;p&gt;Now let's move to some examples!&lt;/p&gt;
&lt;h2 id="animated-examples"&gt;&lt;a class="toclink" href="#animated-examples"&gt;Animated Examples&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The following examples were compiled from several places publicly available on internet. I decided to port them to Python with the help of the Turtle module, center them, adding colors and provide a way to export them in vectorial format.&lt;/p&gt;
&lt;p&gt;Because the browser execute Python via &lt;a href="http://www.skulpt.org/" target="_blank"&gt;Skulpt&lt;/a&gt; and Colorsys isn't supported yet, the animations will be Black &amp;amp; White but images with colors and the corresponding code to generate them will be provided. Each animation has a code associated which you can open and fork in &lt;a href="https://repl.it/" target="_blank"&gt;Repl.it&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WARNING: The animations you are about to see are quite large in size, it is recommended to see them only with a good connection. The Repl snippet may not work since it uses your resources so mobile users might not be able to see it properly.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Note: Skulpt uses YOUR BROWSER to render and to make the animation so if in any case you experience delays, lags or strange behaviour it may be a problem with the browser, replaying the animation or reloading the page should fix most issues. It may not work properly on mobile.&lt;/p&gt;
&lt;p&gt;The examples are ordered by their complexity (my own judgement though), so the best ones are at the end.&lt;/p&gt;
&lt;h2 id="koch-snowflake"&gt;&lt;a class="toclink" href="#koch-snowflake"&gt;Koch-Snowflake"&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F--F--F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F+F--F+F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 7&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Koch-Snowflake_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Koch-Snowflake-With-Python?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="quadratic-koch-island"&gt;&lt;a class="toclink" href="#quadratic-koch-island"&gt;Quadratic-Koch-Island&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F+F+F+F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F-F+F+FFF-F-F+F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 4&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Quadratic-Koch-Island_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Quadratic-Koch-Island-With-Python?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="crystal"&gt;&lt;a class="toclink" href="#crystal"&gt;Crystal&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F+F+F+F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;FF+F++F+F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 6&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Crystal_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Crystal-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="quadratic-snowflake"&gt;&lt;a class="toclink" href="#quadratic-snowflake"&gt;Quadratic-Snowflake&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F--F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F-F+F+F-F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 6&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Quadratic-Snowflake_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Quadratic-Snowflake-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="box-fractal"&gt;&lt;a class="toclink" href="#box-fractal"&gt;Box-Fractal&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F-F-F-F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F-F+F+F-F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 6&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Box-Fractal_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Box-Fractal-With-Python?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="levy-c-curve"&gt;&lt;a class="toclink" href="#levy-c-curve"&gt;Levy-C-Curve&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;+F--F+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 16&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Levy-C-Curve_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Levy-C-Curve-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="sierpinski-arrowhead"&gt;&lt;a class="toclink" href="#sierpinski-arrowhead"&gt;Sierpinski-Arrowhead&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;YF&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;YF+XF+Y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;XF-YF-X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 10&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Sierpinski-Arrowhead_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Siepinski-Arrowhead-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="siepinski-sieve"&gt;&lt;a class="toclink" href="#siepinski-sieve"&gt;Siepinski-Sieve&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;FXF--FF--FF&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;FF&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;--FXF++FXF++FXF--&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 8&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Siepinski-Sieve_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Siepinski-Sieve-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="board"&gt;&lt;a class="toclink" href="#board"&gt;Board&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F+F+F+F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;FF+F+F+F+FF&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 5&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Board_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Board-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="tiles"&gt;&lt;a class="toclink" href="#tiles"&gt;Tiles&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F+F+F+F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;FF+F-F+F+FF&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 4&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Tiles_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Tiles-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="rings"&gt;&lt;a class="toclink" href="#rings"&gt;Rings&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F+F+F+F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;FF+F+F+F+F+F-F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 4&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Rings_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Rings-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="cross-2"&gt;&lt;a class="toclink" href="#cross-2"&gt;Cross-2&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F+F+F+F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F+F-F+F+F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 6&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Cross-2_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Cross-2-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="pentaplexity"&gt;&lt;a class="toclink" href="#pentaplexity"&gt;Pentaplexity&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F++F++F++F++F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F++F++F+++++F-F++F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 5&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Pentaplexity_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Pentaplexity-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="32-segment-curve"&gt;&lt;a class="toclink" href="#32-segment-curve"&gt;32-Segment-Curve&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F+F+F+F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-F+F-F-F+F+FF-F+F+FF+F-F-FF+FF-FF+F+F-FF-F-F+FF-F-F+F+F-F+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 3&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
   &lt;source data-src="/blog/images/fractals/450/32-Segment-Curve_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-32-Segment-Curve-With-Python?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="peano-gosper-curve"&gt;&lt;a class="toclink" href="#peano-gosper-curve"&gt;Peano-Gosper-Curve&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;FX&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X+YF++YF-FX--FXFX-YF+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-FX+YFYF++YF+FX--FX-Y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 6&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Peano-Gosper-Curve_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Peano-Gosper-Curve-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="sierpinski-curve"&gt;&lt;a class="toclink" href="#sierpinski-curve"&gt;Sierpinski-Curve&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F+XF+F+XF&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;XF-F+F-XF+F+XF-F+F-X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 8&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Sierpinski-Curve_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Siepinski-Curve-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="krishna-anklets"&gt;&lt;a class="toclink" href="#krishna-anklets"&gt;Krishna-Anklets&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; -X--X&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;XFX--XFX&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 9&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Krishna-Anklets_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Krishna-Anklets-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="quadratic-gosper"&gt;&lt;a class="toclink" href="#quadratic-gosper"&gt;Quadratic-Gosper&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;YF&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;XFX-YF-YF+FX+FX-YF-YFFX+YF+FXFXYF-FX+YF+FXFX+YF-FXYF-YF-FX+FX+YFYF-&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="s2"&gt;&amp;quot;Y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;+FXFX-YF-YF+FX+FXYF+FX-YFYF-FX-YF+FXYFYF-FX-YFFX+FX+YF-YF-FX+FX+YFY&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 3&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Quadratic-Gosper_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Quadratic-Gosper-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="moore-curve"&gt;&lt;a class="toclink" href="#moore-curve"&gt;Moore-Curve&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;LFL-F-LFL&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;L&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;+RF-LFL-FR+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;R&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-LF+RFR+FL-&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 8&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Moore-Curve_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Moore-Curve-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="hilberts-curve"&gt;&lt;a class="toclink" href="#hilberts-curve"&gt;Hilberts-Curve&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;L&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;L&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;+RF-LFL-FR+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;R&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-LF+RFR+FL-&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 9&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Hilberts-Curve_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Hilbert-Curve-With-Python?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="hilbert-curve-ii"&gt;&lt;a class="toclink" href="#hilbert-curve-ii"&gt;Hilbert-Curve-II&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;XFYFX+F+YFXFY-F-XFYFX&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;YFXFY-F-XFYFX+F+YFXFY&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 6&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Hilbert-Curve-II_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Hilbert-Curve-II-With-Python?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="peano-curve"&gt;&lt;a class="toclink" href="#peano-curve"&gt;Peano-Curve"&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F+F-F-F-F+F+F+F-F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 5&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Peano-Curve_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Peano-Curve-With-Python?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="cross"&gt;&lt;a class="toclink" href="#cross"&gt;Cross&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F+F+F+F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F+FF++F+F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 6&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Cross_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Cross-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="triangle"&gt;&lt;a class="toclink" href="#triangle"&gt;Triangle&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F+F+F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F-F+F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 9&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Triangle_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Triangle-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="dragon-curve"&gt;&lt;a class="toclink" href="#dragon-curve"&gt;Dragon-Curve&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;FX&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X+YF+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-FX-Y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 16&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Dragon-Curve_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Dragon-Curve-With-Python?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="terdragon-curve"&gt;&lt;a class="toclink" href="#terdragon-curve"&gt;TerDragon-Curve&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;F-F+F&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 10&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/TerDragon-Curve_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-TerDragon-Curve-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="twin-dragon-curve"&gt;&lt;a class="toclink" href="#twin-dragon-curve"&gt;Twin-Dragon-Curve&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;FX+FX&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X+YF+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-FX-Y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 16&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/Twin-Dragon-Curve_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-Twin-Dragon-Curve-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="threedragon-curve"&gt;&lt;a class="toclink" href="#threedragon-curve"&gt;ThreeDragon-Curve&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;axiom&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;FX+FX+FX&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;X+YF+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-FX-Y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="c1"&gt;# TOP: 15&lt;/span&gt;
&lt;span class="n"&gt;angle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="two-column"&gt;
&lt;video class="b-lazy" autoplay loop&gt;
    &lt;source data-src="/blog/images/fractals/450/ThreeDragon-Curve_450x450.mp4" type="video/mp4"&gt;
&lt;/video&gt;

&lt;iframe class="b-lazy" height="549px" width="469px" data-src="https://repl.it/@ELC/Drawing-ThreeDragon-Curve-With-Python-and-Turtle?lite=true&amp;outputonly=1" scrolling="no" frameborder="no" allowtransparency="true" allowfullscreen="true" sandbox="allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-modals"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;h2 id="code"&gt;&lt;a class="toclink" href="#code"&gt;Code&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All the examples above were produced by the same code and some challenges emerged when working on it, mainly to keep the fractal centered (or at least as much as possible), dealing with colors, inversions and offsets and to export it quickly in a vectorial format. Here I will show you the most basic version, if you want to know how I dealt with those challenges, leave me a comment and I will make a Part 2.&lt;/p&gt;
&lt;p&gt;This version plots in black and white and with no export functionalities&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;turtle&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_l_system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axiom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;start_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;axiom&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;iters&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;axiom&lt;/span&gt;
    &lt;span class="n"&gt;end_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iters&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;end_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;start_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;start_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end_string&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;end_string&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;draw_l_system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;F&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;+&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axiom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_offset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;x_offset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset_angle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;450&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;450&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;inst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_l_system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axiom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;turtle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Turtle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;wn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;turtle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;wn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x_offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y_offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset_angle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;down&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pensize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;draw_l_system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hideturtle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;wn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exitonclick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="code-explanation"&gt;&lt;a class="toclink" href="#code-explanation"&gt;Code Explanation&lt;/a&gt;&lt;/h2&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;turtle&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;First we need to import the Turtle Module&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_l_system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axiom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;start_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;axiom&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;iters&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;axiom&lt;/span&gt;
    &lt;span class="n"&gt;end_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iters&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;end_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;start_string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;start_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;end_string&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;end_string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then we need to generate the L-System which will be the set of instructions for the turtle. We define a function called &lt;code&gt;create_l_system&lt;/code&gt; which receives the number of iterations, the axiom and the production rules. It starts with the axiom and uses an auxiliary variable called &lt;code&gt;end_string&lt;/code&gt; if iteration is equal to 0 it will return the axiom since some fractals can be plot with iterations equal to 0. Rules here are assumed to be dictionaries, so the key will be unique and represents the symbol and the value represents what should be replaced with. So we join all the replacements for each symbol and we end up with the string for the next iteration.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;draw_l_system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;F&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;distance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;+&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then we define a &lt;code&gt;draw_l_system&lt;/code&gt; which takes the turtle, the set of instructions (the output of the L-System), the angle for the turn right/left and the length of each individual line. It consist of a simple elif structure for each of the previously defined commands.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axiom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y_offset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;x_offset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;offset_angle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;450&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;450&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;

    &lt;span class="n"&gt;inst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_l_system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axiom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;turtle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Turtle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;wn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;turtle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;wn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;x_offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;y_offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset_angle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;down&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pensize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;draw_l_system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;angle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hideturtle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;wn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exitonclick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And finally the &lt;code&gt;main&lt;/code&gt; function, it receives all the parameters it need for the generation of the L-Systems and also &lt;code&gt;y_offset&lt;/code&gt;, &lt;code&gt;x_offset&lt;/code&gt;, &lt;code&gt;offset_angle&lt;/code&gt;, &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt;. The first three represent the offset of the turtle, this is merely for positioning the plot as we want inside the canvas. &lt;/p&gt;
&lt;p&gt;The function first generates a set of instructions and stores it in &lt;code&gt;inst&lt;/code&gt; then it initializes the turtle and the screen and it positions the turtle in the defined position, then it plots the instructions and wait for a click to close.&lt;/p&gt;
&lt;h2 id="special-considerations"&gt;&lt;a class="toclink" href="#special-considerations"&gt;Special Considerations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As I mentioned earlier there are lots of limitations here, first we are not including the possibility of moving the turtle without drawing, this would require another symbol, it isn't either a symbol for going backwards, or remember previous positions. This weren't necessary for all the fractals you've seen but for some other (like fractal trees), these symbols are required.&lt;/p&gt;
&lt;h2 id="additional-resources"&gt;&lt;a class="toclink" href="#additional-resources"&gt;Additional Resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are lots of resources in internet about fractals both from the programming and from the math perspective. I will show you two that I find really interesting: The 3Blue1Brown for math and the CodingTrain for code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Coding Train&lt;/strong&gt;&lt;/p&gt;
&lt;div class="youtube-container"&gt;
    &lt;iframe class="b-lazy" width="560px" height="315px" data-src="https://www.youtube.com/embed/f6ra024-ASY?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen&gt;&lt;/iframe&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;3Blue1Brown&lt;/strong&gt;&lt;/p&gt;
&lt;div class="youtube-container"&gt;
    &lt;iframe class="b-lazy" width="560px" height="315px" data-src="https://www.youtube.com/embed/gB9n2gHsHN4?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen&gt;&lt;/iframe&gt;
    &lt;/div&gt;
&lt;/div&gt;
&lt;h2 id="sources-and-references"&gt;&lt;a class="toclink" href="#sources-and-references"&gt;Sources and References&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This post was inspired by a &lt;a href="http://mathworld.wolfram.com/LindenmayerSystem.html" target="_blank"&gt;Math World post&lt;/a&gt;, the &lt;a href="http://paulbourke.net/fractals/lsys/" target="_blank"&gt;Paul Broke Blog&lt;/a&gt; and an university assignment for Genetic Algorithms.&lt;/p&gt;</content><category term="Programming"></category><category term="Python"></category><category term="Fractals"></category><category term="Turtle"></category></entry><entry><title>Configuring FastAI with Google Colab</title><link href="https://elc.github.io/posts/fastai-colab-deep-learning" rel="alternate"></link><published>2018-09-28T00:00:00-03:00</published><updated>2018-09-28T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2018-09-28:/posts/fastai-colab-deep-learning</id><summary type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/fast-colab-deep-learning/fast-colab-deep-learning_headerimage.png"&gt;&lt;img alt="FastAi Header Image" class="b-lazy" data-src="/blog/images/fast-colab-deep-learning/fast-colab-deep-learning_headerimage.png" src="https://elc.github.io/blog/images/fast-colab-deep-learning/fast-colab-deep-learning_headerimage-thumbnail.png" width="1246"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Nowadays there are lots of tutorials and material to learn Artificial Inteligence, Machine Learning and Deep Learning but whenever you want to do something interesting you notice you need a Nvidia GPU. In this tutorial we are going to solve this issue with a free cloud solution.&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;EDIT: this post …&lt;/strong&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/fast-colab-deep-learning/fast-colab-deep-learning_headerimage.png"&gt;&lt;img alt="FastAi Header Image" class="b-lazy" data-src="/blog/images/fast-colab-deep-learning/fast-colab-deep-learning_headerimage.png" src="https://elc.github.io/blog/images/fast-colab-deep-learning/fast-colab-deep-learning_headerimage-thumbnail.png" width="1246"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;Nowadays there are lots of tutorials and material to learn Artificial Inteligence, Machine Learning and Deep Learning but whenever you want to do something interesting you notice you need a Nvidia GPU. In this tutorial we are going to solve this issue with a free cloud solution.&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;EDIT: this post is now OBSOLETE since the FastAI Team prepare specific tutorial for this an other setups, this could be found in &lt;a href="#https://course.fast.ai/index.html" target="_blank"&gt;their official course page&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;WARNING: The fastai framework is migrating because of the release of PyTorch 1.0. The content of this notebook will be updated but the code might not work until the version 1.x of fastai has clear instructions about its installation.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First of all I'm going to introduce some definitions and concepts just for those that are not familiar with these topics. If you just want to  jump directly to the tutorialn, scroll down to the &lt;a href="#tutorial"&gt;&lt;strong&gt;tutorial section&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="introduction"&gt;&lt;a class="toclink" href="#introduction"&gt;Introduction&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;More often than not I find people who are confused about the relationship of the terms "Artificial Inteligence", "Machine Learning" and "Deep Learning". Let's try to explain it a bit (no rigorous math!). Artificial Inteligence is the broad term, lots of areas fall into this category for example, neural networks, computer vision, natural language, chatbots, sentiment analisis, etc. When people used Machine Learning they refer to more "statistical" methods such as Support Vector Machines (SVMs), Classification Trees, K-Means, Mean-Shift, etc. Another are is Deep Learning which is the narrower of all since it focuses just in one topic artificial neural networks, there are several type of neural networks and when they have several "hidden layers" we are talking about "Deep" Learning.&lt;/p&gt;
&lt;p&gt;If you want to know more about which are the fields of Computer Science, I suggest you to watch &lt;a href="https://www.youtube.com/watch?v=SzJ46YA_RaA" target="_blank"&gt;Map of Computer Science by Domain of Science&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;One of the most common libraries to solve Machine Learning Problems is Scikit-Learn and they provide a beautiful roadmap to understand which algorithms are inside this field and their categorizations (there may be much more but it's enough for an introduction):&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/fast-colab-deep-learning/sklearn-roadmap.png"&gt;&lt;img alt="Scikit-Learn Roadmap" class="b-lazy" data-src="/blog/images/fast-colab-deep-learning/sklearn-roadmap.png" src="https://elc.github.io/blog/images/fast-colab-deep-learning/sklearn-roadmap-thumbnail.png" width="2122"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Simirlarly there is a beautiful image which shows all the types of neural networks, along with &lt;a href="https://towardsdatascience.com/the-mostly-complete-chart-of-neural-networks-explained-3fb6f2367464"&gt;a medium post&lt;/a&gt; explaining them.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/fast-colab-deep-learning/neural-networks-types.png"&gt;&lt;img alt="Scikit-Learn Roadmap" class="b-lazy" data-src="/blog/images/fast-colab-deep-learning/neural-networks-types.png" src="https://elc.github.io/blog/images/fast-colab-deep-learning/neural-networks-types-thumbnail.png" width="2000"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="the-problem"&gt;&lt;a class="toclink" href="#the-problem"&gt;The problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Generally, when talking about computers, the more you want to scale and parallelize, the simpler the algorithm should be. Complex algorithms are slow and don't usually scale well, this is why nowadays there is a lot of hype arround AI. Artificial Neural Nets were first proposed in 1943! Why nobody used them until now? Because although they are simple, they need lots of computations and CPUs aren't that good at that, they have to perform logic operation, memory management and many other things. But GPUs on the other hand were created primarily for aritmetic calculations and it is today that we have GPUs that powerful that Deep Learning and Machine Learning are indeed possible in a reasonable amount of time. Other things influenced too of course, such as cloud services, fast disks and lots of research.&lt;/p&gt;
&lt;p&gt;This is why according to the Gartner Hype Cycle Deep Learning is at its peak:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/fast-colab-deep-learning/gartnet-2017.jpg"&gt;&lt;img alt="Gartnet Cycle" class="b-lazy" data-src="/blog/images/fast-colab-deep-learning/gartnet-2017.jpg" src="https://elc.github.io/blog/images/fast-colab-deep-learning/gartnet-2017-thumbnail.jpg" width="1385"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So, just buy a GPU and you will be ready for Deep learning! Not so fast, frameworks and libraries work better on GPUs, but those should be Nvidia and support CUDA and cuDNN which is another requirement many won't meet. Additionally, the GPU is generally (unless you are building a server), the most expensive part of a PC System.&lt;/p&gt;
&lt;p&gt;This is why finding a way to experiment with deep learning may not be free. There are several cloud based services where you can rent a GPU for hour and even seconds and they are pretty cheap, but if you just want to try without paying, those might not be a suitable option. This is where &lt;a href="https://colab.research.google.com/"&gt;Colaboratory&lt;/a&gt; comes in, it's a service offered by Google which provides free GPU (up to 12 GB of Video RAM) for your computations, it also supports colaboratory editing (like Google Docs) and it can be saved in Google Drive or Github.&lt;/p&gt;
&lt;h2 id="tools-and-requirements"&gt;&lt;a class="toclink" href="#tools-and-requirements"&gt;Tools and requirements&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Developing software implies learning a programming language, usually a framework, learn arquitecture patterns, best practices and of course a lot more. But AI goes in another direction, it is math heavy (although you can build amazing stuff with high school algebra), it realies in a predifined set of algorithms and the cutting edge news usually comes in the form of a scientific paper rather than a fancy framework. Because of this, two different roles emerged, in one hand, there is the Software Developer and in the other hand there is the Data Scientist, both know data structures, algorithms, programming but their skillset is quite different. We will see which tools you will need to start digging in AI and Deep Learning.&lt;/p&gt;
&lt;p&gt;First you will need to learn programming basics, control flow structures and decisions, it isn't needed to know OOP or Functional programming although it might be useful for some. Second, you will need to know Python, it is the most used language in the field and it seems it will continue like that and third you will need to feel confortable with a new "environment" called notebooks, particularly Jupyter Notebooks. I know some might disagree, specially in the last point, there are lots of opinions and I strongly believe that if you learn these things you will be able to watch most of video-tutorials on youtube and you will be on track without issues. You can convice yourselves looking at this survey, based on 10.153 responses:&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/fast-colab-deep-learning/data-science-tools.png"&gt;&lt;img alt="data-science-tools" class="narrow b-lazy" data-src="/blog/images/fast-colab-deep-learning/data-science-tools.png" src="https://elc.github.io/blog/images/fast-colab-deep-learning/data-science-tools-thumbnail.png" width="601"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once you know this prerequirements, you will face a very common dilemma, which Deep Learning Framework should you use? Using a framework is recommended (although doing it manually help a lot to understand the underlying process) so for this tutorial I chose fastai because it's built over PyTorch which is known for being the most pythonic and thus the friendlier to begginers.&lt;/p&gt;
&lt;h2 id="tutorial"&gt;&lt;a class="toclink" href="#tutorial"&gt;Tutorial&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In case you want to see the final result, this is the final notebook:&lt;/p&gt;
&lt;script src="https://gist.github.com/ELC/756040fe84a8bb3d14c59b0e997c84e9.js"&gt;&lt;/script&gt;

&lt;p&gt;Now I'm going to explain how that notebook works.&lt;/p&gt;
&lt;p&gt;First we have to make sure GPU acceleration is enabled, to achieved this by setting "Hardware Accelerator" to GPU in the menu: &lt;code&gt;Edit &amp;gt; Notebook settings &amp;gt; set "Hardware Accelerator" to GPU&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/fast-colab-deep-learning/colab-edit.png"&gt;&lt;img alt="Colab Edit" class="narrow b-lazy" data-src="/blog/images/fast-colab-deep-learning/colab-edit.png" src="https://elc.github.io/blog/images/fast-colab-deep-learning/colab-edit-thumbnail.png" width="484"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="gallery" href="/blog/images/fast-colab-deep-learning/colab-gpu.png"&gt;&lt;img alt="Colab GPU" class="narrow b-lazy" data-src="/blog/images/fast-colab-deep-learning/colab-gpu.png" src="https://elc.github.io/blog/images/fast-colab-deep-learning/colab-gpu-thumbnail.png" width="532"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since Fastai is not built in Colaboratory, we have to install it manually, the best way is by source since it's in rapid development and the realeses found via pip could be outdated. Additionally we can install PyTorch 3.1 with CUDA 9.1 in the same cell.&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;%%bash

&lt;span class="k"&gt;if&lt;/span&gt; ! &lt;span class="o"&gt;[&lt;/span&gt; -d fastai &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
git clone https://github.com/fastai/fastai.git
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; fastai

git pull

pip -q install .

pip -q install http://download.pytorch.org/whl/cu91/torch-0.3.1-cp36-cp36m-linux_x86_64.whl

pip -q install torchvision
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now we can import fastai with all its modules&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fastai.imports&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fastai.transforms&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fastai.conv_learner&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fastai.model&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fastai.dataset&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fastai.sgdr&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;fastai.plots&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And we are ready to go! You can check that the GPU is enabled with the following command:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Is CUDA and CUDNN enabled: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cuda&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_available&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backends&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cudnn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And if you want to check exactly how much Video RAM you have you can run the following snippet:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ln&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;sf&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nvidia&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;smi&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nvidia&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;smi&lt;/span&gt;
&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;pip3&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;gputil&lt;/span&gt;
&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;pip3&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;psutil&lt;/span&gt;
&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="n"&gt;pip3&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;psutil&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;humanize&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;GPUtil&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nn"&gt;GPU&lt;/span&gt;

&lt;span class="n"&gt;GPUs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GPU&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getGPUs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;gpu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GPUs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;psutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getpid&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Number of GPUs: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GPUs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Gen RAM Free: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;naturalsize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;psutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;virtual_memory&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; | Proc size: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;naturalsize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memory_info&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rss&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;GPU RAM Free: &lt;/span&gt;&lt;span class="si"&gt;{0:.0f}&lt;/span&gt;&lt;span class="s2"&gt;MB | Used: &lt;/span&gt;&lt;span class="si"&gt;{1:.0f}&lt;/span&gt;&lt;span class="s2"&gt;MB | Util &lt;/span&gt;&lt;span class="si"&gt;{2:3.0f}&lt;/span&gt;&lt;span class="s2"&gt;% | Total &lt;/span&gt;&lt;span class="si"&gt;{3:.0f}&lt;/span&gt;&lt;span class="s2"&gt;MB&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gpu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memoryFree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gpu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memoryUsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gpu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memoryUtil&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gpu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;memoryTotal&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is indeed possible to do Deep Learning with GPU without paying nothing, we just have to wait until the right set of technologies is available.&lt;/p&gt;</content><category term="Programming"></category><category term="Python"></category><category term="FastAI"></category><category term="deep-learning"></category><category term="Jupyter Notebooks"></category><category term="Colab"></category></entry><entry><title>Create one executable file for a Flask app with PyInstaller</title><link href="https://elc.github.io/posts/executable-flask-pyinstaller" rel="alternate"></link><published>2018-02-24T00:00:00-03:00</published><updated>2018-02-24T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2018-02-24:/posts/executable-flask-pyinstaller</id><summary type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/flask_pyinstaller/flask-pyinstaller_headerimage.png"&gt;&lt;img alt="Flask_pyinstaller_logo" class="b-lazy" data-src="/blog/images/flask_pyinstaller/flask-pyinstaller_headerimage.png" src="https://elc.github.io/blog/images/flask_pyinstaller/flask-pyinstaller_headerimage-thumbnail.png" width="1401"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EDIT 2019.05.03:&lt;/strong&gt; The content order was change and the ideas were express more succinctly.&lt;/p&gt;


&lt;p&gt;Having a single executable file could be a great advantage in so many cases and nowadays more a more desktop applications are using web technologies (React Native, Cordova, Ionic, etc.). It was time for …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/flask_pyinstaller/flask-pyinstaller_headerimage.png"&gt;&lt;img alt="Flask_pyinstaller_logo" class="b-lazy" data-src="/blog/images/flask_pyinstaller/flask-pyinstaller_headerimage.png" src="https://elc.github.io/blog/images/flask_pyinstaller/flask-pyinstaller_headerimage-thumbnail.png" width="1401"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EDIT 2019.05.03:&lt;/strong&gt; The content order was change and the ideas were express more succinctly.&lt;/p&gt;


&lt;p&gt;Having a single executable file could be a great advantage in so many cases and nowadays more a more desktop applications are using web technologies (React Native, Cordova, Ionic, etc.). It was time for the Python stack to join the Group via PyFlaDesk, a simple script to combine Flask, Qt and PyInstaller to create desktop Apps.&lt;/p&gt;


&lt;p&gt;I wanted to create a single executable desktop application and since PyInstaller was there for a while I thought it would be pretty easy, it turns out that after after trying lots of solutions from Stack overflow, Quora and several blogs without success, I decided to post how I managed to solve the problem.&lt;/p&gt;
&lt;p&gt;Note: A full list of the resources mentioned is &lt;a href="#additional-resources"&gt;below&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you just want to read the solution, scroll down to the &lt;a href="#solution"&gt;solution section&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="the-problem"&gt;&lt;a class="toclink" href="#the-problem"&gt;The Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Well, Flask is a &lt;strong&gt;WEB&lt;/strong&gt; framework (or Microframework as it desribes itself), used to create WEBsites that will be served by a WEB server and view from a WEB browser. Problems emerge when we try to replace 'WEB' with desktop in the previous sentence, we are trying to force something built for a particular scenario with its limitations to work in a completely different one.&lt;/p&gt;
&lt;h2 id="motivation"&gt;&lt;a class="toclink" href="#motivation"&gt;Motivation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Desktop applications aren't the most popular use for Python, those positions belongs to Web Development, DevOps and Data Science and, among the technologies used in the Web Development, Django and Flask are the most popular frameworks.&lt;/p&gt;
&lt;p&gt;Using the tools one already knows for something completely different is a great advantage, in this case we want to create a desktop app with a single executable file from a web app built with Flask.&lt;/p&gt;
&lt;p&gt;Some of the main advantages of the self-contained (also known as portable) software are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No virtual environment required.&lt;/li&gt;
&lt;li&gt;Knowing which software is installed in the destination machine isn't necessary.&lt;/li&gt;
&lt;li&gt;No installation required, just copy and paste or execute from removable drive.&lt;/li&gt;
&lt;li&gt;Easier to tell the final user where is the program and how to execute it.&lt;/li&gt;
&lt;li&gt;Harder (yet not impossible) to reverse engineer the software.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are some obvious disadvantages such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Since all dependencies are included, files could get BIG (Hello World app in Flask is about 25MB).&lt;/li&gt;
&lt;li&gt;No version control support for binaries.&lt;/li&gt;
&lt;li&gt;If you consume self-contained software you have to &lt;strong&gt;trust&lt;/strong&gt; your provider about its safety.&lt;/li&gt;
&lt;li&gt;Working with external files, databases and other external sources has to be strongly tested.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This are some points to consider, they could be advantages or disadvantages depending on the case:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You treat the software as a black box.&lt;/li&gt;
&lt;li&gt;When a new version is released you just replace the file and you're done.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="flask-comes-into-the-action"&gt;&lt;a class="toclink" href="#flask-comes-into-the-action"&gt;Flask comes into the action&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you attempt to port a web app to a desktop one without changing the framework chances are you will use a lightweight framework like Flask. Now, how do you create a desktop app? Using a desktop framework (Qt, Tk, wx, etc), the most commonly used framework for this task is Qt. The idea is to create a minimal web browser capable of rendering HTML and then, execute the flask application server and browse to the url of the server inside this browser.&lt;/p&gt;
&lt;p&gt;But what are the differences between creating a web browser and using the systems default? Well, first of all, you assume there will be one, and that that one would be able to render all the HTML, CSS and JS you are using, that could not be the case. More often than not we found ourselves developing software for old operating systems (aka Windows XP o older).&lt;/p&gt;
&lt;p&gt;Sounds easy and actually it can be done, I was contributing to a script to achieve this very goal &lt;a href="https://elc.github.io/link/pyfladesk_repo" target="_blank"&gt;PyFladesk&lt;/a&gt;. There are some concerns about which version of Qt is the appropriate and the convenience of one over the other.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If all you use is Flask for served static or pseudo static content you could tried &lt;a href="http://pythonhosted.org/Frozen-Flask/" target="_blank"&gt;Frozen Flask&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="solution"&gt;&lt;a class="toclink" href="#solution"&gt;Solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After reading all the previous posts and some of the &lt;a href="https://pythonhosted.org/PyInstaller/" target="_blank"&gt;PyInstaller docs&lt;/a&gt;. I found that some people actually solved it! But, the solution they propose was editing the spec file, which is generated after a first run of PyInstaller. I thought that solution was a hack and not the proper way to achieve what I wanted.&lt;/p&gt;
&lt;p&gt;So I tried to understand what the changes in the spec file did and it turned out that that changes was to copy the folders Flask uses into the file directory/file (Actually one of the proposed solutions was build and then copy paste the folders, but besides being unpractical it wouldn't work with one file builds). After a little reasearch, I came across the command line arguments to achieve the same.&lt;/p&gt;
&lt;p&gt;Windows:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pyinstaller -w -F --add-data &amp;quot;templates;templates&amp;quot; --add-data &amp;quot;static;static&amp;quot; app.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Linux (NOT TESTED):&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pyinstaller -w -F --add-data &amp;quot;templates:templates&amp;quot; --add-data &amp;quot;static:static&amp;quot; app.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will create a folder &lt;code&gt;dist&lt;/code&gt; with our executable ready to be shipped. The executable will open the main window of our app.&lt;/p&gt;
&lt;p&gt;It first started as a contribution for the &lt;a href="https://elc.github.io/link/pyfladesk_repo" target="_blank"&gt;PyFladesk&lt;/a&gt; project and then, I realize that since Qt is quite big, our executable were big too. The example app of that repository is 70 MB (much of which was the Qt Component for displaying HTML (WebEngine)). This is reasonable taking into account that we were shipping a self contain web browser.&lt;/p&gt;
&lt;p&gt;There is no simple solution to the size problem but some suggestions are proposed in a &lt;a href="#the-size-problem"&gt;following section&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="tutorial"&gt;&lt;a class="toclink" href="#tutorial"&gt;Tutorial&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you haven't already, install it with pip (if you use virtual environments you should install it inside it)&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install pyinstaller
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Some parameters to consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;F&lt;/code&gt; - Bundles everything in a single file&lt;/li&gt;
&lt;li&gt;&lt;code&gt;w&lt;/code&gt; - Avoid displaying a console&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--add-data&lt;/code&gt; - Add Folders to the directory/executable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since Flask relies on a directory structure you should pass it to the folder, in the example case we only have two folders: &lt;code&gt;templates&lt;/code&gt; and &lt;code&gt;static&lt;/code&gt;, in case you use a database or some other directory structure you may adapt this.&lt;/p&gt;
&lt;p&gt;Note: For more complex scenarios check the &lt;a href="https://pythonhosted.org/PyInstaller/usage.html" target="_blank"&gt;PyInstaller Docs&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="the-size-problem"&gt;&lt;a class="toclink" href="#the-size-problem"&gt;The Size Problem&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Is the project using as few dependencies as possible? If yes, continue reading, if not check and then come back. Make sure you create a virtual environment for your project and execute PyInstaller from there, if the size is still big, I recommend you to check one of these:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use Virtual Environments and install everything you need there, including PyInstaller (but nothing more!)&lt;/li&gt;
&lt;li&gt;Check if all your dependences are really necessary, try to use the standard library when possible&lt;/li&gt;
&lt;li&gt;Check if your biggest dependencies could be replaced with lightweight alternatives&lt;/li&gt;
&lt;li&gt;Use one-dir option and then see what are the biggest dlls and if you can exclude them&lt;/li&gt;
&lt;li&gt;Use the &lt;a href="http://pyinstaller.readthedocs.io/en/stable/advanced-topics.html#using-pyi-archive-viewer" target="_blank"&gt;ArchiveViewer.py script&lt;/a&gt; that's part of PyInstaller and exclude everything you don't need&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using PyInstaller and Flask is not as hard as people may experience if you have the correct knowledge but it requires a bit of work to get a clean, lightweight file. However, it's possible to create executable with complex apps, with special directory structure, databases and so on, but don't expect that to be a tiny file.&lt;/p&gt;
&lt;h2 id="additional-resources"&gt;&lt;a class="toclink" href="#additional-resources"&gt;Additional Resources&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The following are the pages where this topic was mentioned and I couldn't find a proper answer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/32149892/flask-application-built-using-pyinstaller-not-rendering-index-html" target="_blank"&gt;Flask application built using pyinstaller not rendering index.html - jinja2.exceptions.TemplateNotFound&lt;/a&gt; (Stack Overflow)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/47832309/pyinstaller-on-flask-app-import-error" target="_blank"&gt;Pyinstaller on Flask app, import error&lt;/a&gt; (Stack Overflow)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/47018930/using-pyinstaller-on-python-flask-application-to-create-executable" target="_blank"&gt;Using Pyinstaller on Python Flask Application to create Executable&lt;/a&gt; (Stack Overflow)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/40191441/python-2-7-12-trying-to-build-an-executable-file-using-pyinstaller-i-keep-gett" target="_blank"&gt;Python 2.7.12, trying to build an executable file using pyinstaller. I keep getting the below error&lt;/a&gt; (Stack Overflow)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.quora.com/Can-I-convert-a-Flask-application-into-an-executable-file-that-runs-on-Windows-like-an-exe-file" target="_blank"&gt;Can I convert a Flask application into an executable file that runs on Windows like an .exe file?&lt;/a&gt; (Quora)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/Python/comments/21evjn/is_it_possible_to_deploydistribute_flask_as_an/" target="_blank"&gt;Is it possible to deploy/distribute Flask as an executable for desktop use?&lt;/a&gt; (Reddit)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://mapopa.blogspot.com.ar/2013/10/flask-and-pyinstaller-notice.html" target="_blank"&gt;Flask and pyinstaller notice&lt;/a&gt; (Personal Website)&lt;/li&gt;
&lt;/ul&gt;</content><category term="Programming"></category><category term="Python"></category><category term="Flask"></category><category term="PyInstaller"></category></entry><entry><title>Haskell pattern matching in Python</title><link href="https://elc.github.io/posts/haskell-pattern-matching-in-python" rel="alternate"></link><published>2018-02-18T00:00:00-03:00</published><updated>2018-02-18T00:00:00-03:00</updated><author><name>Ezequiel Leonardo Castaño</name></author><id>tag:elc.github.io,2018-02-18:/posts/haskell-pattern-matching-in-python</id><summary type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/haskell_python/haskell_python_headerimage.png"&gt;&lt;img alt="Haskell Header Image" class="b-lazy" data-src="/blog/images/haskell_python/haskell_python_headerimage.png" src="https://elc.github.io/blog/images/haskell_python/haskell_python_headerimage-thumbnail.png" width="1371"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;I started to learn a bit of Haskell and one of its features amazed me: Pattern Matching. Then, unexpectably, I notice Python 3 have them too but with a different name: Extended Tuple Unpacking. Okay, it's not exactly the same but you can get quite similar functionalities if you master …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a class="gallery" href="/blog/images/haskell_python/haskell_python_headerimage.png"&gt;&lt;img alt="Haskell Header Image" class="b-lazy" data-src="/blog/images/haskell_python/haskell_python_headerimage.png" src="https://elc.github.io/blog/images/haskell_python/haskell_python_headerimage-thumbnail.png" width="1371"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;I started to learn a bit of Haskell and one of its features amazed me: Pattern Matching. Then, unexpectably, I notice Python 3 have them too but with a different name: Extended Tuple Unpacking. Okay, it's not exactly the same but you can get quite similar functionalities if you master it. This post is inspired by this &lt;a href="https://stackoverflow.com/questions/6967632/unpacking-extended-unpacking-and-nested-extended-unpacking" target="_blank"&gt;question&lt;/a&gt;&lt;/p&gt;


&lt;h2 id="pattern-what"&gt;&lt;a class="toclink" href="#pattern-what"&gt;Pattern what?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pattern matching is a feature of Haskell that allows us to think in terms of &lt;a href="https://stackoverflow.com/a/6957292/7690767" target="_blank"&gt;wholemeal programming&lt;/a&gt;, this means that we forget about the specific details of what we are working with. For example: Think in terms of first and last element instead of index 0 and index -1. This way of thinking has a very strong link with another common functional pattern: Recursive Functions&lt;/p&gt;
&lt;h2 id="is-this-a-python-or-a-haskell-thing"&gt;&lt;a class="toclink" href="#is-this-a-python-or-a-haskell-thing"&gt;Is this a Python or a Haskell thing?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Haskell is much older than Python and there are other languages that implements it besides Haskell so we can't say it's from either. But it turned out to be something that useful that it was incorporated into Python in the &lt;a href="https://www.python.org/dev/peps/pep-3132/#id3" target="_blank"&gt;PEP 3132&lt;/a&gt; (In case you don't know, PEPs are the python enhancenment proposals, where all new features are asked and discussed).&lt;/p&gt;
&lt;h2 id="how-does-it-look-like"&gt;&lt;a class="toclink" href="#how-does-it-look-like"&gt;How does it look like?&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="tuple-unpacking"&gt;&lt;a class="toclink" href="#tuple-unpacking"&gt;Tuple Unpacking&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You probably used and make yourself familiar with typica tuple unpacking&lt;/p&gt;
&lt;p&gt;Either because you did this:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or this:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or maybe you use it at the top of a for loop:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;John&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Peter&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="extended-tuple-unpacking"&gt;&lt;a class="toclink" href="#extended-tuple-unpacking"&gt;Extended Tuple Unpacking&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These are common uses of the tuple unpacking but a more powerful feature is built on top of it: The extended version, which uses the &lt;a href="https://docs.python.org/3/tutorial/controlflow.html#unpacking-argument-lists" target="_blank"&gt;Unpacking Argument Lists (splat)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Lets see some examples:&lt;/p&gt;
&lt;p&gt;We will use the following list for this example:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;list_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Which by the way can also be written as:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;list_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or even more simplified:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;list_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4 id="examples"&gt;&lt;a class="toclink" href="#examples"&gt;Examples&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Get the first item of a list:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list_&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Get the last item of a list:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list_&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Get the first and the last item of a list&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list_&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="caveats"&gt;&lt;a class="toclink" href="#caveats"&gt;Caveats&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although it may seem quite simple an easy, there are lots of ways to get it wrong:&lt;/p&gt;
&lt;div class="highlight "&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;XYZ&amp;quot;&lt;/span&gt;                 &lt;span class="c1"&gt;# ERROR -- too many values to unpack&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;XY&amp;quot;&lt;/span&gt;                  &lt;span class="c1"&gt;# ERROR -- need more than 1 value to unpack&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;this&amp;#39;&lt;/span&gt;       &lt;span class="c1"&gt;# ERROR -- too many values to unpack&lt;/span&gt;
&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;         &lt;span class="c1"&gt;# ERROR -- two starred expressions in assignment&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;                  &lt;span class="c1"&gt;# ERROR -- too many values to unpack&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;                &lt;span class="c1"&gt;# ERROR - &amp;#39;int&amp;#39; object is not iterable&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="is-there-any-logic-behind-it"&gt;&lt;a class="toclink" href="#is-there-any-logic-behind-it"&gt;Is there any logic behind it?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Of course there is! This is programming and for a full explanation I recommend you to read the PEP and this &lt;a href="https://stackoverflow.com/a/6968451" target="_blank"&gt;answer&lt;/a&gt;&lt;/p&gt;</content><category term="Programming"></category><category term="Haskell"></category><category term="Python"></category><category term="Tuple Unpacking"></category></entry></feed>