<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://george-gca.github.io/feed.xml" rel="self" type="application/atom+xml"/><link href="https://george-gca.github.io/" rel="alternate" type="text/html"/><updated>2025-12-24T02:59:17+00:00</updated><id>https://george-gca.github.io/feed.xml</id><title type="html">blank</title><entry><title type="html">A comprehensive guide to Python best practices</title><link href="https://george-gca.github.io/blog/2025/python-best-practices/" rel="alternate" type="text/html" title="A comprehensive guide to Python best practices"/><published>2025-11-24T23:44:15+00:00</published><updated>2025-11-24T23:44:15+00:00</updated><id>https://george-gca.github.io/blog/2025/python-best-practices</id><content type="html" xml:base="https://george-gca.github.io/blog/2025/python-best-practices/"><![CDATA[<p>A guide of best practices for developing in Python. Inspired by Rui Maranhao’s <a href="https://gist.github.com/ruimaranhao/4e18cbe3dad6f68040c32ed6709090a3">gist</a>.</p> <h2 id="in-general">In General</h2> <blockquote> <p>“Beautiful is better than ugly.” - <a href="https://peps.python.org/pep-0020/">PEP 20</a></p> </blockquote> <h3 id="general-development-guidelines">General Development Guidelines</h3> <h4 id="explicit-is-better-than-implicit---pep-20">“Explicit is better than implicit” - <a href="https://peps.python.org/pep-0020/">PEP 20</a></h4> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">process_data</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">30</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Process data with explicit parameters.</span><span class="sh">"""</span>
    <span class="c1"># Parameters are clear and visible
</span>    <span class="k">return</span> <span class="n">data</span><span class="p">.</span><span class="nf">decode</span><span class="p">(</span><span class="n">encoding</span><span class="p">)</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">process_data</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Process data with hidden defaults.</span><span class="sh">"""</span>
    <span class="c1"># Magic values hidden inside function
</span>    <span class="k">return</span> <span class="n">data</span><span class="p">.</span><span class="nf">decode</span><span class="p">(</span><span class="sh">'</span><span class="s">utf-8</span><span class="sh">'</span><span class="p">)</span>  <span class="c1"># What encoding? Why?
</span></code></pre></div></div> <h4 id="readability-counts---pep-20">“Readability counts.” - <a href="https://peps.python.org/pep-0020/">PEP 20</a></h4> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">calculate_total_price</span><span class="p">(</span><span class="n">items</span><span class="p">,</span> <span class="n">tax_rate</span><span class="p">):</span>
    <span class="n">subtotal</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">price</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">)</span>
    <span class="n">tax</span> <span class="o">=</span> <span class="n">subtotal</span> <span class="o">*</span> <span class="n">tax_rate</span>
    <span class="n">total</span> <span class="o">=</span> <span class="n">subtotal</span> <span class="o">+</span> <span class="n">tax</span>
    <span class="k">return</span> <span class="n">total</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">calc</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">t</span><span class="p">):</span>
    <span class="k">return</span> <span class="nf">sum</span><span class="p">(</span><span class="n">x</span><span class="p">.</span><span class="n">p</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">i</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">+</span> <span class="n">t</span><span class="p">)</span>
</code></pre></div></div> <h4 id="anybody-can-fix-anything">“Anybody can fix anything.”</h4> <p>Don’t create artificial barriers or “ownership” of code. If you see a bug or improvement opportunity in any part of the codebase, fix it.</p> <blockquote> <p>This principle comes from Khan Academy’s development philosophy.</p> </blockquote> <p><strong>Yes</strong></p> <ul> <li>See a typo in someone else’s module? Fix it.</li> <li>Found a bug in a different team’s code? Submit a fix.</li> <li>Notice outdated documentation? Update it.</li> </ul> <p><strong>No</strong></p> <ul> <li>“That’s not my module, I won’t touch it.”</li> <li>“I’ll just work around this bug in their code.”</li> <li>Leaving broken code for the “owner” to fix.</li> </ul> <h4 id="fix-each-issue-bad-design-wrong-decision-or-poor-code-as-soon-as-it-is-discovered">Fix each issue (bad design, wrong decision, or poor code) <em>as soon as it is discovered</em>.</h4> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># You notice during code review that a function is doing too much.
# Refactor it immediately:
</span>
<span class="k">def</span> <span class="nf">process_user_data</span><span class="p">(</span><span class="n">user</span><span class="p">):</span>
    <span class="nf">validate_user</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
    <span class="nf">save_to_database</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
    <span class="nf">send_welcome_email</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># You notice the problem but add a TODO comment instead:
</span>
<span class="k">def</span> <span class="nf">process_user_data</span><span class="p">(</span><span class="n">user</span><span class="p">):</span>
    <span class="c1"># TODO: This function does too much, should refactor
</span>    <span class="nf">validate_user</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
    <span class="nf">save_to_database</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
    <span class="nf">send_welcome_email</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
    <span class="c1"># TODO will likely never be addressed
</span></code></pre></div></div> <h4 id="now-is-better-than-never---pep-20">“Now is better than never.” - <a href="https://peps.python.org/pep-0020/">PEP 20</a></h4> <p>Don’t wait for the “perfect” solution. Ship working code, then iterate.</p> <p><strong>Yes</strong></p> <ul> <li>Implement a basic working feature, deploy it, gather feedback, improve it.</li> <li>Write simple tests now rather than waiting to design the perfect test suite.</li> </ul> <p><strong>No</strong></p> <ul> <li>Endlessly debating the ideal architecture without writing code.</li> <li>Waiting months to ship because you want every edge case handled.</li> </ul> <h4 id="test-ruthlessly-write-docs-for-new-features">Test ruthlessly. Write docs for new features.</h4> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">divide</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Divide a by b.

    :param a: Numerator
    :param b: Denominator (must be non-zero)
    :returns: Result of a / b
    :raises ValueError: If b is zero
    </span><span class="sh">"""</span>
    <span class="k">if</span> <span class="n">b</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">(</span><span class="sh">"</span><span class="s">Cannot divide by zero</span><span class="sh">"</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">a</span> <span class="o">/</span> <span class="n">b</span>

<span class="c1"># And corresponding tests:
</span><span class="k">class</span> <span class="nc">TestDivide</span><span class="p">(</span><span class="n">unittest</span><span class="p">.</span><span class="n">TestCase</span><span class="p">):</span>
    <span class="k">def</span> <span class="nf">test_divide_positive_numbers</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="nf">assertEqual</span><span class="p">(</span><span class="nf">divide</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="mi">5</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">test_divide_by_zero_raises_error</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="k">with</span> <span class="n">self</span><span class="p">.</span><span class="nf">assertRaises</span><span class="p">(</span><span class="nb">ValueError</span><span class="p">):</span>
            <span class="nf">divide</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">divide</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">a</span> <span class="o">/</span> <span class="n">b</span>  <span class="c1"># No docs, no tests, will crash on zero
</span></code></pre></div></div> <h4 id="even-more-important-than-test-driven-developmenthuman-driven-development">Even more important than Test-Driven Development–<em>Human-Driven Development</em></h4> <p>Write code for humans first, machines second.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">ShoppingCart</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">items</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="k">def</span> <span class="nf">add_item</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">item</span><span class="p">):</span>
        <span class="sh">"""</span><span class="s">Add an item to the cart.</span><span class="sh">"""</span>
        <span class="n">self</span><span class="p">.</span><span class="n">items</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">get_total</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="sh">"""</span><span class="s">Calculate total price of all items.</span><span class="sh">"""</span>
        <span class="k">return</span> <span class="nf">sum</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">price</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">self</span><span class="p">.</span><span class="n">items</span><span class="p">)</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">SC</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">i</span> <span class="o">=</span> <span class="p">[]</span>

    <span class="k">def</span> <span class="nf">a</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">x</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">i</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">t</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="nf">sum</span><span class="p">(</span><span class="n">z</span><span class="p">.</span><span class="n">p</span> <span class="k">for</span> <span class="n">z</span> <span class="ow">in</span> <span class="n">self</span><span class="p">.</span><span class="n">i</span><span class="p">)</span>
</code></pre></div></div> <h4 id="these-guidelines-mayand-probably-willchange">These guidelines may–and probably will–change.</h4> <p>Be flexible and open to improving practices as you learn and as the field evolves. What works today might not be the best approach tomorrow.</p> <h2 id="in-particular">In Particular</h2> <h3 id="style">Style</h3> <p>Follow <a href="https://peps.python.org/pep-0008/">PEP 8</a>, when sensible.</p> <h4 id="naming">Naming</h4> <ul> <li>Variables, functions, methods, packages, modules <ul> <li><code class="language-plaintext highlighter-rouge">lower_case_with_underscores</code></li> </ul> </li> <li>Classes and Exceptions <ul> <li><code class="language-plaintext highlighter-rouge">CapWords</code></li> </ul> </li> <li>Protected methods and internal functions <ul> <li><code class="language-plaintext highlighter-rouge">_single_leading_underscore(self, ...)</code></li> <li><em>Note</em>: Leading underscores help IDEs identify protected/private members and can trigger “unused” warnings for internal helpers</li> </ul> </li> <li>Private methods <ul> <li><code class="language-plaintext highlighter-rouge">__double_leading_underscore(self, ...)</code></li> </ul> </li> <li>Constants <ul> <li><code class="language-plaintext highlighter-rouge">ALL_CAPS_WITH_UNDERSCORES</code></li> </ul> </li> </ul> <p><strong>About underscore prefixes:</strong></p> <p>Using <code class="language-plaintext highlighter-rouge">_</code> prefix for protected/private functions helps your IDE and linters understand your intent:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># mymodule.py
</span>
<span class="k">def</span> <span class="nf">_internal_helper</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Internal function - not part of public API.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="n">data</span><span class="p">.</span><span class="nf">strip</span><span class="p">().</span><span class="nf">lower</span><span class="p">()</span>

<span class="k">def</span> <span class="nf">public_function</span><span class="p">(</span><span class="n">text</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Public API function.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="nf">_internal_helper</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>

<span class="c1"># IDE will warn that _internal_helper is "unused" if not called internally
# IDE will mark it as protected/internal in code navigation
</span></code></pre></div></div> <p><em>Rationale</em>: IDEs like PyCharm and VS Code use the underscore prefix to:</p> <ul> <li>Activate “unused code” warnings for internal helpers</li> <li>Indicate these functions shouldn’t be imported with <code class="language-plaintext highlighter-rouge">from module import *</code></li> <li>Show different icons/colors in code navigation to distinguish public vs internal APIs</li> </ul> <h5 id="general-naming-guidelines">General Naming Guidelines</h5> <p>Avoid one-letter variables (esp. <code class="language-plaintext highlighter-rouge">l</code>, <code class="language-plaintext highlighter-rouge">O</code>, <code class="language-plaintext highlighter-rouge">I</code>).</p> <p><em>Exception</em>: In very short blocks, when the meaning is clearly visible from the immediate context</p> <p><strong>Fine</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">e</span> <span class="ow">in</span> <span class="n">elements</span><span class="p">:</span>
    <span class="n">e</span><span class="p">.</span><span class="nf">mutate</span><span class="p">()</span>
</code></pre></div></div> <p>Avoid redundant labeling.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">audio</span>

<span class="n">core</span> <span class="o">=</span> <span class="n">audio</span><span class="p">.</span><span class="nc">Core</span><span class="p">()</span>
<span class="n">controller</span> <span class="o">=</span> <span class="n">audio</span><span class="p">.</span><span class="nc">Controller</span><span class="p">()</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">audio</span>
<span class="kn">from</span> <span class="n">audio</span> <span class="kn">import</span> <span class="o">*</span>

<span class="n">core</span> <span class="o">=</span> <span class="n">audio</span><span class="p">.</span><span class="nc">AudioCore</span><span class="p">()</span>
<span class="n">controller</span> <span class="o">=</span> <span class="n">audio</span><span class="p">.</span><span class="nc">AudioController</span><span class="p">()</span>
</code></pre></div></div> <p>Prefer “reverse notation”.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">elements</span> <span class="o">=</span> <span class="bp">...</span>
<span class="n">elements_active</span> <span class="o">=</span> <span class="bp">...</span>
<span class="n">elements_defunct</span> <span class="o">=</span> <span class="bp">...</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">elements</span> <span class="o">=</span> <span class="bp">...</span>
<span class="n">active_elements</span> <span class="o">=</span> <span class="bp">...</span>
<span class="n">defunct_elements</span> <span class="bp">...</span>
</code></pre></div></div> <p>Avoid reusing the same variable name for different purposes.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Each variable has a single, clear purpose
</span><span class="n">user_input</span> <span class="o">=</span> <span class="nf">input</span><span class="p">(</span><span class="sh">"</span><span class="s">Enter a number: </span><span class="sh">"</span><span class="p">)</span>
<span class="n">user_number</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="n">user_input</span><span class="p">)</span>
<span class="n">squared_number</span> <span class="o">=</span> <span class="n">user_number</span> <span class="o">**</span> <span class="mi">2</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Result: </span><span class="si">{</span><span class="n">squared_number</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Processing different types of data
</span><span class="n">raw_data</span> <span class="o">=</span> <span class="nf">fetch_data_from_api</span><span class="p">()</span>
<span class="n">processed_data</span> <span class="o">=</span> <span class="nf">clean_data</span><span class="p">(</span><span class="n">raw_data</span><span class="p">)</span>
<span class="n">validated_data</span> <span class="o">=</span> <span class="nf">validate_data</span><span class="p">(</span><span class="n">processed_data</span><span class="p">)</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># 'data' means something different each time
</span><span class="n">data</span> <span class="o">=</span> <span class="nf">input</span><span class="p">(</span><span class="sh">"</span><span class="s">Enter a number: </span><span class="sh">"</span><span class="p">)</span>  <span class="c1"># data is a string
</span><span class="n">data</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>                   <span class="c1"># now data is an int
</span><span class="n">data</span> <span class="o">=</span> <span class="n">data</span> <span class="o">**</span> <span class="mi">2</span>                   <span class="c1"># now data is the squared result
</span><span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Result: </span><span class="si">{</span><span class="n">data</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>           <span class="c1"># confusing!
</span></code></pre></div></div> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Reusing 'result' for unrelated things
</span><span class="n">result</span> <span class="o">=</span> <span class="nf">calculate_tax</span><span class="p">(</span><span class="n">price</span><span class="p">)</span>
<span class="nf">save_to_database</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="nf">send_email</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>  <span class="c1"># result now means something completely different
</span><span class="n">result</span> <span class="o">=</span> <span class="nf">validate_input</span><span class="p">(</span><span class="n">form</span><span class="p">)</span>  <span class="c1"># and now something else again
</span></code></pre></div></div> <p><em>Rationale</em>: Reusing variable names makes code harder to debug, understand, and maintain. Each variable should represent one concept throughout its scope.</p> <h4 id="indentation">Indentation</h4> <p>Up to you, but be consistent. <a href="https://thenewstack.io/spaces-vs-tabs-a-20-year-debate-and-now-this-what-the-hell-is-wrong-with-go/">Enough said</a>.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="https://media.giphy.com/media/l0IylSajlbPRFxH8Y/giphy-480.webp 480w,https://media.giphy.com/media/l0IylSajlbPRFxH8Y/giphy-800.webp 800w,https://media.giphy.com/media/l0IylSajlbPRFxH8Y/giphy-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="https://media.giphy.com/media/l0IylSajlbPRFxH8Y/giphy.gif" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <p>However, note that: A tab could be a different number of columns depending on your environment, but a space is always one column. In terms of how many spaces (or tabs) constitutes indentation, it’s more important to be consistent throughout your code than to use any specific tab stop value.</p> <h4 id="equality-checking">Equality checking</h4> <p>Avoid comparing to <code class="language-plaintext highlighter-rouge">True</code>, <code class="language-plaintext highlighter-rouge">False</code> or <code class="language-plaintext highlighter-rouge">None</code>.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">attr</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">True!</span><span class="sh">'</span><span class="p">)</span>

<span class="k">if</span> <span class="n">attr</span> <span class="ow">is</span> <span class="bp">True</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">True!</span><span class="sh">'</span><span class="p">)</span>

<span class="k">if</span> <span class="ow">not</span> <span class="n">attr</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">False!</span><span class="sh">'</span><span class="p">)</span>

<span class="k">if</span> <span class="n">attr</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">None</span><span class="sh">'</span><span class="p">)</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">attr</span> <span class="o">==</span> <span class="bp">True</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">True!</span><span class="sh">'</span><span class="p">)</span>

<span class="k">if</span> <span class="n">attr</span> <span class="o">==</span> <span class="bp">False</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">False!</span><span class="sh">'</span><span class="p">)</span>

<span class="k">if</span> <span class="n">attr</span> <span class="o">==</span> <span class="bp">None</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">'</span><span class="s">None</span><span class="sh">'</span><span class="p">)</span>
</code></pre></div></div> <h4 id="list-comprehensions">List comprehensions</h4> <p>Use list comprehension when possible.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span>
<span class="n">b</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span>  <span class="ow">in</span> <span class="n">a</span>  <span class="k">if</span> <span class="n">i</span> <span class="o">&gt;</span> <span class="mi">4</span><span class="p">]</span>

<span class="c1">#Or (filter is this case; map could also be more appropriate in other cases)
</span><span class="n">b</span> <span class="o">=</span> <span class="nf">filter</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="mi">4</span><span class="p">,</span> <span class="n">a</span><span class="p">)</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">a</span> <span class="o">=</span> <span class="p">[</span><span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span>
<span class="n">b</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">a</span><span class="p">:</span>
    <span class="k">if</span>  <span class="n">i</span> <span class="o">&gt;</span> <span class="mi">4</span><span class="p">:</span>
        <span class="n">b</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div></div> <h4 id="keyword-with-and-files">Keyword <code class="language-plaintext highlighter-rouge">with</code> and files</h4> <p>The <code class="language-plaintext highlighter-rouge">with</code> statement ensures that clean-up code is executed. When opening a file, <code class="language-plaintext highlighter-rouge">with</code> will make sure that the file is closed after the <code class="language-plaintext highlighter-rouge">with</code> block.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="sh">'</span><span class="s">file.txt</span><span class="sh">'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="n">do_something_with_f</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">f</span> <span class="o">=</span> <span class="nf">open</span><span class="p">(</span><span class="sh">'</span><span class="s">file.txt</span><span class="sh">'</span><span class="p">)</span>
<span class="n">do_something_with_f</span>
<span class="n">f</span><span class="p">.</span><span class="nf">close</span><span class="p">()</span>
</code></pre></div></div> <h4 id="imports">Imports</h4> <p>Import entire modules instead of individual symbols within a module. For example, for a top-level module <code class="language-plaintext highlighter-rouge">canteen</code> that has a file <code class="language-plaintext highlighter-rouge">canteen/sessions.py</code>,</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">canteen</span>
<span class="kn">import</span> <span class="n">canteen.sessions</span>
<span class="kn">from</span> <span class="n">canteen</span> <span class="kn">import</span> <span class="n">sessions</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">canteen</span> <span class="kn">import</span> <span class="n">get_user</span>  <span class="c1"># Symbol from canteen/__init__.py
</span><span class="kn">from</span> <span class="n">canteen.sessions</span> <span class="kn">import</span> <span class="n">get_session</span>  <span class="c1"># Symbol from canteen/sessions.py
</span></code></pre></div></div> <p><em>Exception</em>: For third-party code where documentation explicitly says to import individual symbols.</p> <p><em>Rationale</em>: Avoids circular imports. See <a href="https://stackabuse.com/python-circular-imports/">here</a>.</p> <p>Put all imports at the top of the page with three sections, each separated by a blank line, in this order:</p> <ol> <li>System imports</li> <li>Third-party imports</li> <li>Local source tree imports</li> </ol> <p><em>Rationale</em>: Makes it clear where each module is coming from.</p> <h4 id="documentation">Documentation</h4> <p>Follow <a href="https://peps.python.org/pep-0257/">PEP 257</a>’s docstring guidelines. <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">reStructured Text</a> and <a href="http://sphinx-doc.org/">Sphinx</a> can help to enforce these standards.</p> <p>When possible, use one-line docstrings for obvious functions.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="sh">"""</span><span class="s">Return the pathname of ``foo``.</span><span class="sh">"""</span>
</code></pre></div></div> <p>Multiline docstrings should include</p> <ul> <li>Summary line</li> <li>Use case, if appropriate</li> <li>Args</li> <li>Return type and semantics, unless <code class="language-plaintext highlighter-rouge">None</code> is returned</li> </ul> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="sh">"""</span><span class="s">Train a model to classify Foos and Bars.

Usage::
</span><span class="gp">
    &gt;&gt;&gt;</span> <span class="kn">import</span> <span class="n">klassify</span>
    <span class="o">&gt;&gt;&gt;</span> <span class="n">data</span> <span class="o">=</span> <span class="p">[(</span><span class="sh">"</span><span class="s">green</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">foo</span><span class="sh">"</span><span class="p">),</span> <span class="p">(</span><span class="sh">"</span><span class="s">orange</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">bar</span><span class="sh">"</span><span class="p">)]</span>
    <span class="o">&gt;&gt;&gt;</span> <span class="n">classifier</span> <span class="o">=</span> <span class="n">klassify</span><span class="p">.</span><span class="nf">train</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>

<span class="s">:param train_data: A list of tuples of the form ``(color, label)``.
:rtype: A :class:`Classifier &lt;Classifier&gt;`
</span><span class="sh">"""</span>
</code></pre></div></div> <p>Notes</p> <ul> <li>Use action words (“Return”) rather than descriptions (“Returns”).</li> <li>Document <code class="language-plaintext highlighter-rouge">__init__</code> methods in the docstring for the class.</li> </ul> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Person</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">A simple representation of a human being.

    :param name: A string, the person</span><span class="sh">'</span><span class="s">s name.
    :param age: An int, the person</span><span class="sh">'</span><span class="s">s age.
    </span><span class="sh">"""</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">age</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span>
        <span class="n">self</span><span class="p">.</span><span class="n">age</span> <span class="o">=</span> <span class="n">age</span>
</code></pre></div></div> <h5 id="alternative-docstring-formats">Alternative Docstring Formats</h5> <p>While the examples above use reStructuredText (reST) format, there are other popular docstring styles used in the Python community. Choose one and be consistent throughout your project.</p> <p><strong>NumPy/SciPy Style</strong></p> <p>Popular in scientific computing, more readable for complex functions with many parameters.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">calculate_statistics</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">weights</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">ddof</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">
    Calculate mean and standard deviation of data.

    Parameters
    ----------
    data : array_like
        Input data array.
    weights : array_like, optional
        Weights for each value in data. Default is None.
    ddof : int, optional
        Delta degrees of freedom. Default is 0.

    Returns
    -------
    mean : float
        Arithmetic mean of the data.
    std : float
        Standard deviation of the data.

    Raises
    ------
    ValueError
        If data is empty.

    Examples
    --------
</span><span class="gp">    &gt;&gt;&gt;</span> <span class="nf">calculate_statistics</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">])</span>
    <span class="p">(</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">1.4142135623730951</span><span class="p">)</span>
    <span class="sh">"""</span>
    <span class="k">pass</span>
</code></pre></div></div> <p><strong>Google Style</strong></p> <p>Clean and readable, popular in many open-source projects.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">calculate_statistics</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">weights</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">ddof</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Calculate mean and standard deviation of data.

    Args:
        data (array_like): Input data array.
        weights (array_like, optional): Weights for each value in data.
            Defaults to None.
        ddof (int, optional): Delta degrees of freedom. Defaults to 0.

    Returns:
        tuple: A tuple containing:
            - mean (float): Arithmetic mean of the data.
            - std (float): Standard deviation of the data.

    Raises:
        ValueError: If data is empty.

    Examples:
</span><span class="gp">        &gt;&gt;&gt;</span> <span class="nf">calculate_statistics</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">])</span>
        <span class="p">(</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">1.4142135623730951</span><span class="p">)</span>
    <span class="sh">"""</span>
    <span class="k">pass</span>
</code></pre></div></div> <p><strong>Comparison</strong></p> <table> <thead> <tr> <th>Style</th> <th>Best For</th> <th>Tools</th> </tr> </thead> <tbody> <tr> <td><strong>reStructuredText (reST)</strong></td> <td>General Python projects, Sphinx documentation</td> <td>Sphinx, most IDEs</td> </tr> <tr> <td><strong>NumPy/SciPy</strong></td> <td>Scientific computing, data science projects</td> <td>Sphinx with Napoleon extension</td> </tr> <tr> <td><strong>Google</strong></td> <td>Clean, readable docs; Google-style projects</td> <td>Sphinx with Napoleon extension</td> </tr> </tbody> </table> <p><strong>Documentation Generation Tools</strong></p> <p>Beyond Sphinx, several other tools can generate documentation from your docstrings:</p> <table> <thead> <tr> <th>Tool</th> <th>Features</th> <th>Best For</th> </tr> </thead> <tbody> <tr> <td><strong><a href="https://pdoc.dev/">pdoc</a></strong></td> <td>Minimal, clean HTML docs; auto-generates from docstrings; great for small projects</td> <td>Quick documentation without configuration</td> </tr> <tr> <td><strong><a href="https://www.mkdocs.org/">MkDocs</a></strong> with <a href="https://mkdocstrings.github.io/">mkdocstrings</a></td> <td>Modern Material Design theme; Markdown-based; integrates docstrings</td> <td>Beautiful, modern project documentation</td> </tr> <tr> <td><strong><a href="https://docs.python.org/3/library/pydoc.html">Pydoc</a></strong></td> <td>Built-in Python tool; minimal setup; generates HTML or terminal docs</td> <td>Simple projects; documentation without dependencies</td> </tr> <tr> <td><strong><a href="https://machow.github.io/quartodoc/">Quartodoc</a></strong></td> <td>Bridges Quarto and Python; supports multiple docstring formats</td> <td>Data science projects; integrating code with narratives</td> </tr> <tr> <td><strong><a href="https://readthedocs.org/">ReadTheDocs</a></strong></td> <td>Free hosting; integrates with Sphinx; automatic builds from GitHub</td> <td>Open-source projects needing hosted documentation</td> </tr> <tr> <td><strong><a href="https://mkdocstrings.github.io/griffe/">Griffe</a></strong></td> <td>Modern Python doc parser; supports multiple formats; async-friendly</td> <td>Projects requiring flexible docstring extraction</td> </tr> </tbody> </table> <p><strong>Key Points</strong></p> <ul> <li><strong>Be consistent</strong>: Pick one style and use it throughout your project</li> <li><strong>Tool support</strong>: Most documentation generators support multiple docstring formats</li> <li><strong>Team preference</strong>: Follow your team’s or project’s existing convention</li> <li><strong>Readability</strong>: NumPy and Google styles are often more readable for complex functions</li> <li><strong>Integration</strong>: Consider which tools integrate with your CI/CD and hosting platform</li> </ul> <h5 id="on-comments">On comments</h5> <p>Use them sparingly. Prefer code readability to writing a lot of comments. Often, small methods are more effective than comments.</p> <p><em>No</em></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># If the sign is a stop sign
</span><span class="k">if</span> <span class="n">sign</span><span class="p">.</span><span class="n">color</span> <span class="o">==</span> <span class="sh">'</span><span class="s">red</span><span class="sh">'</span> <span class="ow">and</span> <span class="n">sign</span><span class="p">.</span><span class="n">sides</span> <span class="o">==</span> <span class="mi">8</span><span class="p">:</span>
    <span class="nf">stop</span><span class="p">()</span>
</code></pre></div></div> <p><em>Yes</em></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">is_stop_sign</span><span class="p">(</span><span class="n">sign</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">sign</span><span class="p">.</span><span class="n">color</span> <span class="o">==</span> <span class="sh">'</span><span class="s">red</span><span class="sh">'</span> <span class="ow">and</span> <span class="n">sign</span><span class="p">.</span><span class="n">sides</span> <span class="o">==</span> <span class="mi">8</span>

<span class="k">if</span> <span class="nf">is_stop_sign</span><span class="p">(</span><span class="n">sign</span><span class="p">):</span>
    <span class="nf">stop</span><span class="p">()</span>
</code></pre></div></div> <p>When you do write comments, remember: “Strunk and White apply.” - <a href="https://peps.python.org/pep-0008/">PEP 8</a></p> <p>In summary:</p> <blockquote> <p>Use clear, direct language and avoid unnecessary words to ensure a reader’s understanding, as recommended by Strunk and White.</p> </blockquote> <h4 id="line-lengths">Line lengths</h4> <p>Don’t stress over it. 80-100 characters is fine. We have wide screens nowadays.</p> <p>Use parentheses for line continuations.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">wiki</span> <span class="o">=</span> <span class="p">(</span>
    <span class="sh">"</span><span class="s">The Colt Python is a .357 Magnum caliber revolver formerly manufactured </span><span class="sh">"</span>
    <span class="sh">"</span><span class="s">by Colt</span><span class="sh">'</span><span class="s">s Manufacturing Company of Hartford, Connecticut. It is sometimes </span><span class="sh">"</span>
    <span class="sh">'</span><span class="s">referred to as a </span><span class="sh">"</span><span class="s">Combat Magnum</span><span class="sh">"</span><span class="s">. It was first introduced in 1955, the </span><span class="sh">'</span>
    <span class="sh">"</span><span class="s">same year as Smith &amp; Wesson</span><span class="sh">'</span><span class="s">s M29 .44 Magnum.</span><span class="sh">"</span>
<span class="p">)</span>
</code></pre></div></div> <h4 id="string-formatting">String Formatting</h4> <p>Use f-strings (formatted string literals) for string formatting. They are more readable, concise, and faster than older methods.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">name</span> <span class="o">=</span> <span class="sh">"</span><span class="s">Alice</span><span class="sh">"</span>
<span class="n">age</span> <span class="o">=</span> <span class="mi">30</span>
<span class="n">city</span> <span class="o">=</span> <span class="sh">"</span><span class="s">Lisbon</span><span class="sh">"</span>

<span class="c1"># Simple variable interpolation
</span><span class="n">message</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Hello, </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s">!</span><span class="sh">"</span>

<span class="c1"># Expressions inside f-strings
</span><span class="n">info</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s"> is </span><span class="si">{</span><span class="n">age</span><span class="si">}</span><span class="s"> years old and lives in </span><span class="si">{</span><span class="n">city</span><span class="si">}</span><span class="s">.</span><span class="sh">"</span>

<span class="c1"># Formatting numbers
</span><span class="n">price</span> <span class="o">=</span> <span class="mf">19.99</span>
<span class="n">quantity</span> <span class="o">=</span> <span class="mi">3</span>
<span class="n">total</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Total: €</span><span class="si">{</span><span class="n">price</span> <span class="o">*</span> <span class="n">quantity</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="sh">"</span>  <span class="c1"># Total: €59.97
</span>
<span class="c1"># Multi-line f-strings
</span><span class="n">report</span> <span class="o">=</span> <span class="p">(</span>
    <span class="sa">f</span><span class="sh">"</span><span class="s">User Report:</span><span class="se">\n</span><span class="sh">"</span>
    <span class="sa">f</span><span class="sh">"</span><span class="s">  Name: </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="se">\n</span><span class="sh">"</span>
    <span class="sa">f</span><span class="sh">"</span><span class="s">  Age: </span><span class="si">{</span><span class="n">age</span><span class="si">}</span><span class="se">\n</span><span class="sh">"</span>
    <span class="sa">f</span><span class="sh">"</span><span class="s">  City: </span><span class="si">{</span><span class="n">city</span><span class="si">}</span><span class="sh">"</span>
<span class="p">)</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">name</span> <span class="o">=</span> <span class="sh">"</span><span class="s">Alice</span><span class="sh">"</span>
<span class="n">age</span> <span class="o">=</span> <span class="mi">30</span>
<span class="n">city</span> <span class="o">=</span> <span class="sh">"</span><span class="s">Lisbon</span><span class="sh">"</span>

<span class="c1"># Old-style % formatting (avoid)
</span><span class="n">message</span> <span class="o">=</span> <span class="sh">"</span><span class="s">Hello, %s!</span><span class="sh">"</span> <span class="o">%</span> <span class="n">name</span>
<span class="n">info</span> <span class="o">=</span> <span class="sh">"</span><span class="s">%s is %d years old and lives in %s.</span><span class="sh">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">age</span><span class="p">,</span> <span class="n">city</span><span class="p">)</span>

<span class="c1"># str.format() method (verbose)
</span><span class="n">message</span> <span class="o">=</span> <span class="sh">"</span><span class="s">Hello, {}!</span><span class="sh">"</span><span class="p">.</span><span class="nf">format</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
<span class="n">info</span> <span class="o">=</span> <span class="sh">"</span><span class="s">{} is {} years old and lives in {}.</span><span class="sh">"</span><span class="p">.</span><span class="nf">format</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">age</span><span class="p">,</span> <span class="n">city</span><span class="p">)</span>

<span class="c1"># String concatenation (error-prone and hard to read)
</span><span class="n">message</span> <span class="o">=</span> <span class="sh">"</span><span class="s">Hello, </span><span class="sh">"</span> <span class="o">+</span> <span class="n">name</span> <span class="o">+</span> <span class="sh">"</span><span class="s">!</span><span class="sh">"</span>
<span class="n">info</span> <span class="o">=</span> <span class="n">name</span> <span class="o">+</span> <span class="sh">"</span><span class="s"> is </span><span class="sh">"</span> <span class="o">+</span> <span class="nf">str</span><span class="p">(</span><span class="n">age</span><span class="p">)</span> <span class="o">+</span> <span class="sh">"</span><span class="s"> years old and lives in </span><span class="sh">"</span> <span class="o">+</span> <span class="n">city</span> <span class="o">+</span> <span class="sh">"</span><span class="s">.</span><span class="sh">"</span>
</code></pre></div></div> <p><em>Rationale</em>: F-strings (Python 3.6+) are faster, more readable, and less error-prone than <code class="language-plaintext highlighter-rouge">%</code> formatting or <code class="language-plaintext highlighter-rouge">.format()</code>. They allow expressions directly inside the string and make the code’s intent clearer.</p> <p><strong>Advanced f-string features</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Debugging with f-strings (Python 3.8+)
</span><span class="n">x</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">y</span> <span class="o">=</span> <span class="mi">20</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">x</span><span class="o">=</span><span class="si">}</span><span class="s">, </span><span class="si">{</span><span class="n">y</span><span class="o">=</span><span class="si">}</span><span class="s">, </span><span class="si">{</span><span class="n">x</span><span class="o">+</span><span class="n">y</span><span class="o">=</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>  <span class="c1"># x=10, y=20, x+y=30
</span>
<span class="c1"># Calling functions
</span><span class="k">def</span> <span class="nf">get_status</span><span class="p">():</span>
    <span class="k">return</span> <span class="sh">"</span><span class="s">active</span><span class="sh">"</span>

<span class="n">status_msg</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="s">System is </span><span class="si">{</span><span class="nf">get_status</span><span class="p">()</span><span class="si">}</span><span class="sh">"</span>
</code></pre></div></div> <p><strong>Formatting numbers with f-strings</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Format a float to 2 decimal places
</span><span class="n">price</span> <span class="o">=</span> <span class="mf">19.98765</span>
<span class="n">formatted_price</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">price</span><span class="si">:</span><span class="p">.</span><span class="mi">2</span><span class="n">f</span><span class="si">}</span><span class="sh">"</span>  <span class="c1"># '19.99'
</span>
<span class="c1"># Format an integer with leading zeros (e.g., pad to 4 digits)
</span><span class="n">order_number</span> <span class="o">=</span> <span class="mi">42</span>
<span class="n">formatted_order</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">order_number</span><span class="si">:</span><span class="mi">04</span><span class="n">d</span><span class="si">}</span><span class="sh">"</span>  <span class="c1"># '0042'
</span>
<span class="c1"># Right-align a string with spaces using f-strings
</span><span class="n">text</span> <span class="o">=</span> <span class="sh">"</span><span class="s">Python</span><span class="sh">"</span>
<span class="n">width</span> <span class="o">=</span> <span class="mi">12</span>
<span class="n">right_aligned</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">text</span><span class="si">:</span><span class="o">&gt;</span><span class="si">{</span><span class="n">width</span><span class="si">}}</span><span class="sh">"</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"'</span><span class="si">{</span><span class="n">right_aligned</span><span class="si">}</span><span class="sh">'"</span><span class="p">)</span>  <span class="c1"># Output: '      Python'
</span>
<span class="c1"># Or, for left alignment (for comparison):
</span><span class="n">left_aligned</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">text</span><span class="si">:</span><span class="o">&lt;</span><span class="si">{</span><span class="n">width</span><span class="si">}}</span><span class="sh">"</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"'</span><span class="si">{</span><span class="n">left_aligned</span><span class="si">}</span><span class="sh">'"</span><span class="p">)</span>  <span class="c1"># Output: 'Python      '
</span>
<span class="c1"># Format a percentage with 1 decimal place
</span><span class="n">success_rate</span> <span class="o">=</span> <span class="mf">0.857</span>
<span class="n">formatted_rate</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">success_rate</span><span class="si">:</span><span class="p">.</span><span class="mi">1</span><span class="o">%</span><span class="si">}</span><span class="sh">"</span>  <span class="c1"># '85.7%'
</span>
<span class="c1"># Format large numbers with commas
</span><span class="n">population</span> <span class="o">=</span> <span class="mi">1234567</span>
<span class="n">formatted_population</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">population</span><span class="si">:</span><span class="p">,</span><span class="si">}</span><span class="sh">"</span>  <span class="c1"># '1,234,567'
</span>
<span class="c1"># Format large numbers with locale-aware grouping using `:n`
</span><span class="kn">import</span> <span class="n">locale</span>

<span class="n">locale</span><span class="p">.</span><span class="nf">setlocale</span><span class="p">(</span><span class="n">locale</span><span class="p">.</span><span class="n">LC_ALL</span><span class="p">,</span> <span class="sh">''</span><span class="p">)</span>  <span class="c1"># Set to user's default locale
</span><span class="n">large_number</span> <span class="o">=</span> <span class="mf">1234567.89</span>
<span class="n">formatted_number</span> <span class="o">=</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">large_number</span><span class="si">:</span><span class="n">n</span><span class="si">}</span><span class="sh">"</span>  <span class="c1"># e.g., '1,234,567.89' or '1.234.567,89' depending on locale
</span></code></pre></div></div> <h4 id="type-hints">Type Hints</h4> <p>Use type hints to make your code more readable and maintainable. Type hints help IDEs provide better autocomplete, catch errors early, and serve as inline documentation.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">calculate_total</span><span class="p">(</span><span class="n">price</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="n">quantity</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Calculate total price for items.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="n">price</span> <span class="o">*</span> <span class="n">quantity</span>

<span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Return a greeting message.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Hello, </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s">!</span><span class="sh">"</span>

<span class="k">def</span> <span class="nf">process_items</span><span class="p">(</span><span class="n">items</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
    <span class="sh">"""</span><span class="s">Count occurrences of each item.</span><span class="sh">"""</span>
    <span class="n">counts</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">:</span>
        <span class="n">counts</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o">=</span> <span class="n">counts</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="n">counts</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">calculate_total</span><span class="p">(</span><span class="n">price</span><span class="p">,</span> <span class="n">quantity</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Calculate total price for items.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="n">price</span> <span class="o">*</span> <span class="n">quantity</span>  <span class="c1"># What types? Will this work with all inputs?
</span>
<span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Return a greeting message.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Hello, </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s">!</span><span class="sh">"</span>  <span class="c1"># Is name always a string?
</span>
<span class="k">def</span> <span class="nf">process_items</span><span class="p">(</span><span class="n">items</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Count occurrences of each item.</span><span class="sh">"""</span>
    <span class="n">counts</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">:</span>
        <span class="n">counts</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o">=</span> <span class="n">counts</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="n">counts</span>  <span class="c1"># What does this return?
</span></code></pre></div></div> <p><em>Rationale</em>: Type hints improve code clarity, enable better IDE support (autocomplete, refactoring, error detection), and help catch bugs before runtime. Modern IDEs like VS Code and PyCharm use type hints to provide intelligent code completion and warnings.</p> <p><strong>Modern type hints (Python 3.9+)</strong></p> <p>Starting with Python 3.9, you can use built-in types directly instead of importing from <code class="language-plaintext highlighter-rouge">typing</code>. Python 3.10+ also introduces the <code class="language-plaintext highlighter-rouge">|</code> operator for union types.</p> <p><strong>Yes</strong> (Python 3.10+)</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Use built-in types with [] syntax (Python 3.9+)
</span><span class="k">def</span> <span class="nf">process_items</span><span class="p">(</span><span class="n">items</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
    <span class="sh">"""</span><span class="s">Count occurrences of each item.</span><span class="sh">"""</span>
    <span class="n">counts</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">:</span>
        <span class="n">counts</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o">=</span> <span class="n">counts</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="n">counts</span>

<span class="c1"># Use | operator for unions (Python 3.10+)
</span><span class="k">def</span> <span class="nf">find_user</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span> <span class="o">|</span> <span class="bp">None</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Find user by ID, return None if not found.</span><span class="sh">"""</span>
    <span class="k">if</span> <span class="n">user_id</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">"</span><span class="s">Alice</span><span class="sh">"</span>
    <span class="k">return</span> <span class="bp">None</span>

<span class="k">def</span> <span class="nf">process_id</span><span class="p">(</span><span class="n">id_value</span><span class="p">:</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Process ID that can be int or string.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="nf">str</span><span class="p">(</span><span class="n">id_value</span><span class="p">)</span>

<span class="c1"># Multiple union types
</span><span class="k">def</span> <span class="nf">parse_config</span><span class="p">(</span><span class="n">value</span><span class="p">:</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span> <span class="o">|</span> <span class="nb">float</span> <span class="o">|</span> <span class="bp">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Parse configuration value.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="nf">str</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span> <span class="k">else</span> <span class="sh">""</span>
</code></pre></div></div> <p><strong>Older style</strong> (Python 3.5-3.8)</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">typing</span> <span class="kn">import</span> <span class="n">Optional</span><span class="p">,</span> <span class="n">Union</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">Dict</span>

<span class="c1"># Had to import and use capitalized generic types
</span><span class="k">def</span> <span class="nf">process_items</span><span class="p">(</span><span class="n">items</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">]:</span>
    <span class="sh">"""</span><span class="s">Count occurrences of each item.</span><span class="sh">"""</span>
    <span class="n">counts</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">:</span>
        <span class="n">counts</span><span class="p">[</span><span class="n">item</span><span class="p">]</span> <span class="o">=</span> <span class="n">counts</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span>
    <span class="k">return</span> <span class="n">counts</span>

<span class="c1"># Used Optional and Union from typing module
</span><span class="k">def</span> <span class="nf">find_user</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
    <span class="sh">"""</span><span class="s">Find user by ID, return None if not found.</span><span class="sh">"""</span>
    <span class="k">if</span> <span class="n">user_id</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">"</span><span class="s">Alice</span><span class="sh">"</span>
    <span class="k">return</span> <span class="bp">None</span>

<span class="k">def</span> <span class="nf">process_id</span><span class="p">(</span><span class="n">id_value</span><span class="p">:</span> <span class="n">Union</span><span class="p">[</span><span class="nb">int</span><span class="p">,</span> <span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Process ID that can be int or string.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="nf">str</span><span class="p">(</span><span class="n">id_value</span><span class="p">)</span>
</code></pre></div></div> <p><em>Note</em>: If you’re using Python 3.10 or later, prefer the modern syntax with <code class="language-plaintext highlighter-rouge">|</code> and built-in types (<code class="language-plaintext highlighter-rouge">list</code>, <code class="language-plaintext highlighter-rouge">dict</code>, <code class="language-plaintext highlighter-rouge">set</code>, <code class="language-plaintext highlighter-rouge">tuple</code>). For Python 3.9, use built-in types with <code class="language-plaintext highlighter-rouge">[]</code> but continue using <code class="language-plaintext highlighter-rouge">Optional</code> and <code class="language-plaintext highlighter-rouge">Union</code> from <code class="language-plaintext highlighter-rouge">typing</code>. The old style with <code class="language-plaintext highlighter-rouge">List</code>, <code class="language-plaintext highlighter-rouge">Dict</code>, etc. from <code class="language-plaintext highlighter-rouge">typing</code> is now deprecated but still works.</p> <p><strong>More type hint examples</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">typing</span> <span class="kn">import</span> <span class="n">Any</span><span class="p">,</span> <span class="n">Callable</span>

<span class="c1"># Class type hints
</span><span class="k">class</span> <span class="nc">User</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">age</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
        <span class="n">self</span><span class="p">.</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">name</span>
        <span class="n">self</span><span class="p">.</span><span class="n">age</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="n">age</span>

    <span class="k">def</span> <span class="nf">get_info</span><span class="p">(</span><span class="n">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
        <span class="sh">"""</span><span class="s">Return user information.</span><span class="sh">"""</span>
        <span class="k">return</span> <span class="p">{</span><span class="sh">"</span><span class="s">name</span><span class="sh">"</span><span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">name</span><span class="p">,</span> <span class="sh">"</span><span class="s">age</span><span class="sh">"</span><span class="p">:</span> <span class="n">self</span><span class="p">.</span><span class="n">age</span><span class="p">}</span>

<span class="c1"># Callable type hints
</span><span class="k">def</span> <span class="nf">apply_operation</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">operation</span><span class="p">:</span> <span class="n">Callable</span><span class="p">[[</span><span class="nb">int</span><span class="p">],</span> <span class="nb">int</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Apply a function to a number.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="nf">operation</span><span class="p">(</span><span class="n">x</span><span class="p">)</span>

<span class="c1"># Type aliases for complex types
</span><span class="n">UserId</span> <span class="o">=</span> <span class="nb">int</span>
<span class="n">UserData</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span> <span class="o">|</span> <span class="nb">int</span><span class="p">]</span>  <span class="c1"># Python 3.10+
# Or for older versions: dict[str, Union[str, int]]
</span>
<span class="k">def</span> <span class="nf">get_user_data</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="n">UserId</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">UserData</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Get user data by ID.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="p">{</span><span class="sh">"</span><span class="s">name</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">Alice</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">age</span><span class="sh">"</span><span class="p">:</span> <span class="mi">30</span><span class="p">}</span>
</code></pre></div></div> <p><strong>IDE and AI Assistant Benefits</strong></p> <p>With type hints, your IDE and AI coding assistants can:</p> <ul> <li><strong>Autocomplete</strong>: Suggest methods and attributes based on the type</li> <li><strong>Error detection</strong>: Warn you when passing wrong types before running code</li> <li><strong>Refactoring</strong>: Safely rename variables and functions across your codebase</li> <li><strong>Documentation</strong>: Show parameter types in function signatures without reading docs</li> <li><strong>AI assistance</strong>: GitHub Copilot, Codeium, and other AI assistants provide more accurate suggestions when they understand your types</li> </ul> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># IDE knows 'result' is a float, suggests float methods
</span><span class="n">result</span><span class="p">:</span> <span class="nb">float</span> <span class="o">=</span> <span class="nf">calculate_total</span><span class="p">(</span><span class="mf">19.99</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">result</span><span class="p">.</span><span class="nf">is_integer</span><span class="p">()</span>  <span class="c1"># IDE autocompletes this method
</span>
<span class="c1"># IDE warns if you pass wrong types
</span><span class="nf">calculate_total</span><span class="p">(</span><span class="sh">"</span><span class="s">19.99</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">3</span><span class="sh">"</span><span class="p">)</span>  <span class="c1"># IDE shows warning: expected float and int
</span>
<span class="c1"># AI assistants provide better completions with type hints
</span><span class="k">def</span> <span class="nf">process_users</span><span class="p">(</span><span class="n">users</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="nb">dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]])</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
    <span class="c1"># AI knows 'users' is a list of dicts, suggests appropriate operations
</span>    <span class="c1"># AI knows return type should be list of strings
</span>    <span class="k">return</span> <span class="p">[</span><span class="n">user</span><span class="p">[</span><span class="sh">"</span><span class="s">name</span><span class="sh">"</span><span class="p">]</span> <span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">users</span><span class="p">]</span>  <span class="c1"># AI suggests this correctly
</span></code></pre></div></div> <p><em>Note</em>: AI coding assistants like GitHub Copilot use type hints to understand your code’s intent and provide more accurate, context-aware suggestions. Well-typed code gets better AI assistance.</p> <h4 id="leverage-the-standard-library">Leverage the Standard Library</h4> <p>Python’s standard library is extensive and well-tested. Before writing custom solutions or installing third-party packages, check if the standard library already provides what you need. Familiarizing yourself with common standard library modules will make you a more effective Python programmer.</p> <h5 id="collections---specialized-container-data-types">collections - Specialized Container Data Types</h5> <p>The <code class="language-plaintext highlighter-rouge">collections</code> module provides alternatives to built-in containers with additional functionality.</p> <p><strong>Counter - Count hashable objects</strong></p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">collections</span> <span class="kn">import</span> <span class="n">Counter</span>

<span class="c1"># Count occurrences in a list
</span><span class="n">words</span> <span class="o">=</span> <span class="p">[</span><span class="sh">"</span><span class="s">apple</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">banana</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">apple</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">orange</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">banana</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">apple</span><span class="sh">"</span><span class="p">]</span>
<span class="n">word_counts</span> <span class="o">=</span> <span class="nc">Counter</span><span class="p">(</span><span class="n">words</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">word_counts</span><span class="p">)</span>  <span class="c1"># Counter({'apple': 3, 'banana': 2, 'orange': 1})
</span>
<span class="c1"># Get most common items
</span><span class="nf">print</span><span class="p">(</span><span class="n">word_counts</span><span class="p">.</span><span class="nf">most_common</span><span class="p">(</span><span class="mi">2</span><span class="p">))</span>  <span class="c1"># [('apple', 3), ('banana', 2)]
</span>
<span class="c1"># Combine counters
</span><span class="n">more_words</span> <span class="o">=</span> <span class="p">[</span><span class="sh">"</span><span class="s">apple</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">grape</span><span class="sh">"</span><span class="p">]</span>
<span class="n">word_counts</span><span class="p">.</span><span class="nf">update</span><span class="p">(</span><span class="n">more_words</span><span class="p">)</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Manually counting (verbose and error-prone)
</span><span class="n">words</span> <span class="o">=</span> <span class="p">[</span><span class="sh">"</span><span class="s">apple</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">banana</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">apple</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">orange</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">banana</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">apple</span><span class="sh">"</span><span class="p">]</span>
<span class="n">word_counts</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">words</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">word</span> <span class="ow">in</span> <span class="n">word_counts</span><span class="p">:</span>
        <span class="n">word_counts</span><span class="p">[</span><span class="n">word</span><span class="p">]</span> <span class="o">+=</span> <span class="mi">1</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">word_counts</span><span class="p">[</span><span class="n">word</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
</code></pre></div></div> <p><strong>defaultdict - Dictionary with default values</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">collections</span> <span class="kn">import</span> <span class="n">defaultdict</span>

<span class="c1"># Group items by category
</span><span class="n">items</span> <span class="o">=</span> <span class="p">[(</span><span class="sh">"</span><span class="s">fruit</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">apple</span><span class="sh">"</span><span class="p">),</span> <span class="p">(</span><span class="sh">"</span><span class="s">fruit</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">banana</span><span class="sh">"</span><span class="p">),</span> <span class="p">(</span><span class="sh">"</span><span class="s">vegetable</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">carrot</span><span class="sh">"</span><span class="p">)]</span>
<span class="n">grouped</span> <span class="o">=</span> <span class="nf">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span>
<span class="k">for</span> <span class="n">category</span><span class="p">,</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">:</span>
    <span class="n">grouped</span><span class="p">[</span><span class="n">category</span><span class="p">].</span><span class="nf">append</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
<span class="c1"># {'fruit': ['apple', 'banana'], 'vegetable': ['carrot']}
</span></code></pre></div></div> <h5 id="functools---higher-order-functions">functools - Higher-Order Functions</h5> <p><strong>partial - Partial function application</strong></p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">functools</span> <span class="kn">import</span> <span class="n">partial</span>

<span class="k">def</span> <span class="nf">power</span><span class="p">(</span><span class="n">base</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">exponent</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Raise base to the power of exponent.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="n">base</span> <span class="o">**</span> <span class="n">exponent</span>

<span class="c1"># Create specialized functions
</span><span class="n">square</span> <span class="o">=</span> <span class="nf">partial</span><span class="p">(</span><span class="n">power</span><span class="p">,</span> <span class="n">exponent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="n">cube</span> <span class="o">=</span> <span class="nf">partial</span><span class="p">(</span><span class="n">power</span><span class="p">,</span> <span class="n">exponent</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="nf">square</span><span class="p">(</span><span class="mi">5</span><span class="p">))</span>  <span class="c1"># 25
</span><span class="nf">print</span><span class="p">(</span><span class="nf">cube</span><span class="p">(</span><span class="mi">5</span><span class="p">))</span>   <span class="c1"># 125
</span></code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Creating wrapper functions manually
</span><span class="k">def</span> <span class="nf">power</span><span class="p">(</span><span class="n">base</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">exponent</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Raise base to the power of exponent.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="n">base</span> <span class="o">**</span> <span class="n">exponent</span>

<span class="k">def</span> <span class="nf">square</span><span class="p">(</span><span class="n">base</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
    <span class="k">return</span> <span class="nf">power</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="mi">2</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">cube</span><span class="p">(</span><span class="n">base</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
    <span class="k">return</span> <span class="nf">power</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
</code></pre></div></div> <p><strong>lru_cache - Memoization decorator</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">functools</span> <span class="kn">import</span> <span class="n">lru_cache</span>

<span class="nd">@lru_cache</span><span class="p">(</span><span class="n">maxsize</span><span class="o">=</span><span class="mi">128</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">fibonacci</span><span class="p">(</span><span class="n">n</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Calculate nth Fibonacci number with caching.</span><span class="sh">"""</span>
    <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">n</span>
    <span class="k">return</span> <span class="nf">fibonacci</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="nf">fibonacci</span><span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="mi">2</span><span class="p">)</span>

<span class="c1"># Much faster for repeated calls
</span><span class="nf">print</span><span class="p">(</span><span class="nf">fibonacci</span><span class="p">(</span><span class="mi">100</span><span class="p">))</span>  <span class="c1"># Computed instantly due to caching
</span></code></pre></div></div> <h5 id="itertools---iterator-building-blocks">itertools - Iterator Building Blocks</h5> <p><strong>chain - Combine multiple iterables</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">itertools</span> <span class="kn">import</span> <span class="n">chain</span>

<span class="c1"># Combine multiple lists into one
</span><span class="n">list1</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]</span>
<span class="n">list2</span> <span class="o">=</span> <span class="p">[</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">]</span>
<span class="n">combined</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">chain</span><span class="p">(</span><span class="n">list1</span><span class="p">,</span> <span class="n">list2</span><span class="p">))</span>  <span class="c1"># [1, 2, 3, 4, 5, 6]
</span></code></pre></div></div> <p><strong>combinations - All combinations of items</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">itertools</span> <span class="kn">import</span> <span class="n">combinations</span>

<span class="c1"># Get all 2-item combinations
</span><span class="n">items</span> <span class="o">=</span> <span class="p">[</span><span class="sh">'</span><span class="s">A</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">B</span><span class="sh">'</span><span class="p">,</span> <span class="sh">'</span><span class="s">C</span><span class="sh">'</span><span class="p">]</span>
<span class="n">combos</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">combinations</span><span class="p">(</span><span class="n">items</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="c1"># [('A', 'B'), ('A', 'C'), ('B', 'C')]
</span></code></pre></div></div> <p>For more combinatorics utilities, refer to the <a href="https://docs.python.org/3/library/itertools.html">official Python documentation</a>.</p> <p><strong>groupby - Group consecutive items</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">itertools</span> <span class="kn">import</span> <span class="n">groupby</span>

<span class="c1"># Group consecutive items by a key
</span><span class="n">data</span> <span class="o">=</span> <span class="p">[(</span><span class="sh">'</span><span class="s">A</span><span class="sh">'</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="sh">'</span><span class="s">A</span><span class="sh">'</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="sh">'</span><span class="s">B</span><span class="sh">'</span><span class="p">,</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="sh">'</span><span class="s">B</span><span class="sh">'</span><span class="p">,</span> <span class="mi">2</span><span class="p">),</span> <span class="p">(</span><span class="sh">'</span><span class="s">A</span><span class="sh">'</span><span class="p">,</span> <span class="mi">3</span><span class="p">)]</span>
<span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">group</span> <span class="ow">in</span> <span class="nf">groupby</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">]):</span>
    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">key</span><span class="si">}</span><span class="s">: </span><span class="si">{</span><span class="nf">list</span><span class="p">(</span><span class="n">group</span><span class="p">)</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>
<span class="c1"># A: [('A', 1), ('A', 2)]
# B: [('B', 1), ('B', 2)]
# A: [('A', 3)]
</span></code></pre></div></div> <p><strong>islice - Slice an iterator</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">itertools</span> <span class="kn">import</span> <span class="n">islice</span>

<span class="c1"># Get items from an iterator without loading all into memory
</span><span class="k">def</span> <span class="nf">generate_numbers</span><span class="p">():</span>
    <span class="n">n</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
        <span class="k">yield</span> <span class="n">n</span>
        <span class="n">n</span> <span class="o">+=</span> <span class="mi">1</span>

<span class="c1"># Get first 10 even numbers
</span><span class="n">evens</span> <span class="o">=</span> <span class="p">(</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nf">generate_numbers</span><span class="p">()</span> <span class="k">if</span> <span class="n">x</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">first_ten_evens</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">islice</span><span class="p">(</span><span class="n">evens</span><span class="p">,</span> <span class="mi">10</span><span class="p">))</span>  <span class="c1"># [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
</span></code></pre></div></div> <h5 id="pathlib---object-oriented-file-paths">pathlib - Object-Oriented File Paths</h5> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>

<span class="c1"># Modern, readable path operations
</span><span class="n">project_dir</span> <span class="o">=</span> <span class="nc">Path</span><span class="p">(</span><span class="sh">"</span><span class="s">/home/user/project</span><span class="sh">"</span><span class="p">)</span>
<span class="n">config_file</span> <span class="o">=</span> <span class="n">project_dir</span> <span class="o">/</span> <span class="sh">"</span><span class="s">config</span><span class="sh">"</span> <span class="o">/</span> <span class="sh">"</span><span class="s">settings.json</span><span class="sh">"</span>

<span class="k">if</span> <span class="n">config_file</span><span class="p">.</span><span class="nf">exists</span><span class="p">():</span>
    <span class="n">content</span> <span class="o">=</span> <span class="n">config_file</span><span class="p">.</span><span class="nf">read_text</span><span class="p">()</span>

<span class="c1"># List all Python files
</span><span class="n">python_files</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="n">project_dir</span><span class="p">.</span><span class="nf">glob</span><span class="p">(</span><span class="sh">"</span><span class="s">**/*.py</span><span class="sh">"</span><span class="p">))</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">os</span>

<span class="c1"># Old-style string manipulation
</span><span class="n">project_dir</span> <span class="o">=</span> <span class="sh">"</span><span class="s">/home/user/project</span><span class="sh">"</span>
<span class="n">config_file</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="n">project_dir</span><span class="p">,</span> <span class="sh">"</span><span class="s">config</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">settings.json</span><span class="sh">"</span><span class="p">)</span>

<span class="k">if</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="nf">exists</span><span class="p">(</span><span class="n">config_file</span><span class="p">):</span>
    <span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="n">config_file</span><span class="p">,</span> <span class="sh">'</span><span class="s">r</span><span class="sh">'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">content</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="nf">read</span><span class="p">()</span>
</code></pre></div></div> <h5 id="dataclasses---reduce-boilerplate-for-classes">dataclasses - Reduce Boilerplate for Classes</h5> <p><strong>Yes</strong> (Python 3.7+)</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">dataclasses</span> <span class="kn">import</span> <span class="n">dataclass</span>

<span class="nd">@dataclass</span>
<span class="k">class</span> <span class="nc">Point</span><span class="p">:</span>
    <span class="n">x</span><span class="p">:</span> <span class="nb">float</span>
    <span class="n">y</span><span class="p">:</span> <span class="nb">float</span>

    <span class="k">def</span> <span class="nf">distance_from_origin</span><span class="p">(</span><span class="n">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
        <span class="nf">return </span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">x</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">self</span><span class="p">.</span><span class="n">y</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)</span> <span class="o">**</span> <span class="mf">0.5</span>

<span class="n">p</span> <span class="o">=</span> <span class="nc">Point</span><span class="p">(</span><span class="mf">3.0</span><span class="p">,</span> <span class="mf">4.0</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="n">p</span><span class="p">)</span>  <span class="c1"># Point(x=3.0, y=4.0)
</span><span class="nf">print</span><span class="p">(</span><span class="n">p</span><span class="p">.</span><span class="nf">distance_from_origin</span><span class="p">())</span>  <span class="c1"># 5.0
</span></code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Point</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">x</span><span class="p">:</span> <span class="nb">float</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="nb">float</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">x</span>
        <span class="n">self</span><span class="p">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">y</span>

    <span class="k">def</span> <span class="nf">__repr__</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Point(x=</span><span class="si">{</span><span class="n">self</span><span class="p">.</span><span class="n">x</span><span class="si">}</span><span class="s">, y=</span><span class="si">{</span><span class="n">self</span><span class="p">.</span><span class="n">y</span><span class="si">}</span><span class="s">)</span><span class="sh">"</span>

    <span class="k">def</span> <span class="nf">__eq__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="nf">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">Point</span><span class="p">):</span>
            <span class="k">return</span> <span class="nb">NotImplemented</span>
        <span class="k">return</span> <span class="n">self</span><span class="p">.</span><span class="n">x</span> <span class="o">==</span> <span class="n">other</span><span class="p">.</span><span class="n">x</span> <span class="ow">and</span> <span class="n">self</span><span class="p">.</span><span class="n">y</span> <span class="o">==</span> <span class="n">other</span><span class="p">.</span><span class="n">y</span>

    <span class="k">def</span> <span class="nf">distance_from_origin</span><span class="p">(</span><span class="n">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">float</span><span class="p">:</span>
        <span class="nf">return </span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">x</span> <span class="o">**</span> <span class="mi">2</span> <span class="o">+</span> <span class="n">self</span><span class="p">.</span><span class="n">y</span> <span class="o">**</span> <span class="mi">2</span><span class="p">)</span> <span class="o">**</span> <span class="mf">0.5</span>
</code></pre></div></div> <p><em>Rationale</em>: The standard library is well-documented, thoroughly tested, and requires no additional dependencies. Learning these modules will help you write more concise, efficient, and idiomatic Python code.</p> <h3 id="modern-python-features">Modern Python Features</h3> <p>Python continues to evolve with each version, introducing new syntax and features that make code more readable and concise. Here are some significant additions from recent Python versions.</p> <h4 id="assignment-expressions-walrus-operator---python-38">Assignment Expressions (Walrus Operator) - Python 3.8+</h4> <p>The walrus operator <code class="language-plaintext highlighter-rouge">:=</code> allows you to assign values to variables as part of an expression. This is particularly useful in conditions and loops.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Assign and use in one line
</span><span class="nf">if </span><span class="p">(</span><span class="n">n</span> <span class="p">:</span><span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">data</span><span class="p">))</span> <span class="o">&gt;</span> <span class="mi">10</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">List is too long (</span><span class="si">{</span><span class="n">n</span><span class="si">}</span><span class="s"> elements, expected &lt;= 10)</span><span class="sh">"</span><span class="p">)</span>

<span class="c1"># Avoid redundant function calls in while loops
</span><span class="nf">while </span><span class="p">(</span><span class="n">line</span> <span class="p">:</span><span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="nf">readline</span><span class="p">())</span> <span class="o">!=</span> <span class="sh">""</span><span class="p">:</span>
    <span class="nf">process</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>

<span class="c1"># List comprehensions with shared subexpression
</span><span class="n">data</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">]</span>
<span class="n">results</span> <span class="o">=</span> <span class="p">[</span><span class="n">y</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">data</span> <span class="nf">if </span><span class="p">(</span><span class="n">y</span> <span class="p">:</span><span class="o">=</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">2</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">5</span><span class="p">]</span>  <span class="c1"># [6, 8, 10]
</span>
<span class="c1"># Reuse expensive computation in comprehension
</span><span class="n">expensive_results</span> <span class="o">=</span> <span class="p">[</span><span class="n">result</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">data</span>
                    <span class="nf">if </span><span class="p">(</span><span class="n">result</span> <span class="p">:</span><span class="o">=</span> <span class="nf">expensive_function</span><span class="p">(</span><span class="n">x</span><span class="p">))</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">]</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Without walrus operator - less concise
</span><span class="n">n</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="k">if</span> <span class="n">n</span> <span class="o">&gt;</span> <span class="mi">10</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">List is too long (</span><span class="si">{</span><span class="n">n</span><span class="si">}</span><span class="s"> elements, expected &lt;= 10)</span><span class="sh">"</span><span class="p">)</span>

<span class="c1"># Redundant calls
</span><span class="n">line</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="nf">readline</span><span class="p">()</span>
<span class="k">while</span> <span class="n">line</span> <span class="o">!=</span> <span class="sh">""</span><span class="p">:</span>
    <span class="nf">process</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
    <span class="n">line</span> <span class="o">=</span> <span class="nb">file</span><span class="p">.</span><span class="nf">readline</span><span class="p">()</span>

<span class="c1"># Computing twice
</span><span class="n">results</span> <span class="o">=</span> <span class="p">[</span><span class="n">x</span> <span class="o">*</span> <span class="mi">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">data</span> <span class="k">if</span> <span class="n">x</span> <span class="o">*</span> <span class="mi">2</span> <span class="o">&gt;</span> <span class="mi">5</span><span class="p">]</span>
</code></pre></div></div> <p><em>Rationale</em>: The walrus operator reduces code duplication and makes intentions clearer, especially when you need to use a computed value multiple times.</p> <h4 id="positional-only-and-keyword-only-parameters---python-38">Positional-Only and Keyword-Only Parameters - Python 3.8+</h4> <p>Use <code class="language-plaintext highlighter-rouge">/</code> to specify positional-only parameters and <code class="language-plaintext highlighter-rouge">*</code> for keyword-only parameters, making your API more explicit and preventing misuse.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Positional-only parameters (before /)
</span><span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">greeting</span><span class="o">=</span><span class="sh">"</span><span class="s">Hello</span><span class="sh">"</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Name must be positional, greeting can be keyword.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">greeting</span><span class="si">}</span><span class="s">, </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s">!</span><span class="sh">"</span>

<span class="nf">greet</span><span class="p">(</span><span class="sh">"</span><span class="s">Alice</span><span class="sh">"</span><span class="p">)</span>  <span class="c1"># OK
</span><span class="nf">greet</span><span class="p">(</span><span class="sh">"</span><span class="s">Alice</span><span class="sh">"</span><span class="p">,</span> <span class="n">greeting</span><span class="o">=</span><span class="sh">"</span><span class="s">Hi</span><span class="sh">"</span><span class="p">)</span>  <span class="c1"># OK
# greet(name="Alice")  # Error: name is positional-only
</span>
<span class="c1"># Keyword-only parameters (after *)
</span><span class="k">def</span> <span class="nf">create_user</span><span class="p">(</span><span class="n">username</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">email</span><span class="p">,</span> <span class="n">age</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Email and age must be passed as keywords.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="p">{</span><span class="sh">"</span><span class="s">username</span><span class="sh">"</span><span class="p">:</span> <span class="n">username</span><span class="p">,</span> <span class="sh">"</span><span class="s">email</span><span class="sh">"</span><span class="p">:</span> <span class="n">email</span><span class="p">,</span> <span class="sh">"</span><span class="s">age</span><span class="sh">"</span><span class="p">:</span> <span class="n">age</span><span class="p">}</span>

<span class="nf">create_user</span><span class="p">(</span><span class="sh">"</span><span class="s">alice</span><span class="sh">"</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="sh">"</span><span class="s">alice@example.com</span><span class="sh">"</span><span class="p">,</span> <span class="n">age</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>  <span class="c1"># OK
# create_user("alice", "alice@example.com", 30)  # Error: email and age must be keyword
</span>
<span class="c1"># Combining both
</span><span class="k">def</span> <span class="nf">process</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">,</span> <span class="o">/</span><span class="p">,</span> <span class="n">c</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">e</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">a, b are positional-only; c can be either; d, e are keyword-only.</span><span class="sh">"""</span>
    <span class="k">pass</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Ambiguous API without parameter restrictions
</span><span class="k">def</span> <span class="nf">greet</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">greeting</span><span class="o">=</span><span class="sh">"</span><span class="s">Hello</span><span class="sh">"</span><span class="p">):</span>
    <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="si">{</span><span class="n">greeting</span><span class="si">}</span><span class="s">, </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s">!</span><span class="sh">"</span>

<span class="c1"># Users might do this (unclear which is which):
</span><span class="nf">greet</span><span class="p">(</span><span class="n">greeting</span><span class="o">=</span><span class="sh">"</span><span class="s">Alice</span><span class="sh">"</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="sh">"</span><span class="s">Hello</span><span class="sh">"</span><span class="p">)</span>  <span class="c1"># Confusing!
</span></code></pre></div></div> <p><em>Rationale</em>: Explicit parameter types prevent API misuse and make function signatures self-documenting.</p> <h4 id="pattern-matching-structural-pattern-matching---python-310">Pattern Matching (Structural Pattern Matching) - Python 3.10+</h4> <p>The <code class="language-plaintext highlighter-rouge">match</code>/<code class="language-plaintext highlighter-rouge">case</code> statement provides powerful pattern matching similar to switch statements in other languages, but much more flexible.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Simple value matching
</span><span class="k">def</span> <span class="nf">http_status</span><span class="p">(</span><span class="n">status</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="k">match</span> <span class="n">status</span><span class="p">:</span>
        <span class="k">case</span> <span class="mi">200</span><span class="p">:</span>
            <span class="k">return</span> <span class="sh">"</span><span class="s">OK</span><span class="sh">"</span>
        <span class="k">case</span> <span class="mi">404</span><span class="p">:</span>
            <span class="k">return</span> <span class="sh">"</span><span class="s">Not Found</span><span class="sh">"</span>
        <span class="k">case</span> <span class="mi">500</span><span class="p">:</span>
            <span class="k">return</span> <span class="sh">"</span><span class="s">Internal Server Error</span><span class="sh">"</span>
        <span class="k">case</span><span class="w"> </span><span class="k">_</span><span class="p">:</span>
            <span class="k">return</span> <span class="sh">"</span><span class="s">Unknown Status</span><span class="sh">"</span>

<span class="c1"># Pattern matching with structures
</span><span class="k">def</span> <span class="nf">process_command</span><span class="p">(</span><span class="n">command</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="k">match</span> <span class="n">command</span><span class="p">:</span>
        <span class="nf">case </span><span class="p">(</span><span class="sh">"</span><span class="s">quit</span><span class="sh">"</span><span class="p">,):</span>
            <span class="k">return</span> <span class="sh">"</span><span class="s">Exiting...</span><span class="sh">"</span>
        <span class="nf">case </span><span class="p">(</span><span class="sh">"</span><span class="s">load</span><span class="sh">"</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span>
            <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Loading </span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="sh">"</span>
        <span class="nf">case </span><span class="p">(</span><span class="sh">"</span><span class="s">save</span><span class="sh">"</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="nb">format</span><span class="p">):</span>
            <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Saving </span><span class="si">{</span><span class="n">filename</span><span class="si">}</span><span class="s"> as </span><span class="si">{</span><span class="nb">format</span><span class="si">}</span><span class="sh">"</span>
        <span class="k">case</span><span class="w"> </span><span class="k">_</span><span class="p">:</span>
            <span class="k">return</span> <span class="sh">"</span><span class="s">Unknown command</span><span class="sh">"</span>

<span class="c1"># Matching objects and types
</span><span class="k">def</span> <span class="nf">describe</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
    <span class="k">match</span> <span class="n">obj</span><span class="p">:</span>
        <span class="k">case</span> <span class="nf">int</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">if</span> <span class="n">x</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Positive integer: </span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="sh">"</span>
        <span class="k">case</span> <span class="nf">int</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">if</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Negative integer: </span><span class="si">{</span><span class="n">x</span><span class="si">}</span><span class="sh">"</span>
        <span class="k">case</span> <span class="nf">str</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="k">if</span> <span class="nf">len</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
            <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Non-empty string: </span><span class="si">{</span><span class="n">s</span><span class="si">}</span><span class="sh">"</span>
        <span class="k">case</span> <span class="nf">list</span><span class="p">([]):</span>
            <span class="k">return</span> <span class="sh">"</span><span class="s">Empty list</span><span class="sh">"</span>
        <span class="k">case</span> <span class="nf">list</span><span class="p">([</span><span class="n">first</span><span class="p">,</span> <span class="o">*</span><span class="n">rest</span><span class="p">]):</span>
            <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="s">List starting with </span><span class="si">{</span><span class="n">first</span><span class="si">}</span><span class="sh">"</span>
        <span class="k">case</span> <span class="p">{</span><span class="sh">"</span><span class="s">name</span><span class="sh">"</span><span class="p">:</span> <span class="n">name</span><span class="p">,</span> <span class="sh">"</span><span class="s">age</span><span class="sh">"</span><span class="p">:</span> <span class="n">age</span><span class="p">}:</span>
            <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Person: </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s">, age </span><span class="si">{</span><span class="n">age</span><span class="si">}</span><span class="sh">"</span>
        <span class="k">case</span><span class="w"> </span><span class="k">_</span><span class="p">:</span>
            <span class="k">return</span> <span class="sh">"</span><span class="s">Something else</span><span class="sh">"</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Long if-elif chains (less readable)
</span><span class="k">def</span> <span class="nf">http_status</span><span class="p">(</span><span class="n">status</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">status</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">"</span><span class="s">OK</span><span class="sh">"</span>
    <span class="k">elif</span> <span class="n">status</span> <span class="o">==</span> <span class="mi">404</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">"</span><span class="s">Not Found</span><span class="sh">"</span>
    <span class="k">elif</span> <span class="n">status</span> <span class="o">==</span> <span class="mi">500</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">"</span><span class="s">Internal Server Error</span><span class="sh">"</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">"</span><span class="s">Unknown Status</span><span class="sh">"</span>

<span class="k">def</span> <span class="nf">process_command</span><span class="p">(</span><span class="n">command</span><span class="p">:</span> <span class="nb">tuple</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="k">if</span> <span class="nf">len</span><span class="p">(</span><span class="n">command</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="ow">and</span> <span class="n">command</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="sh">"</span><span class="s">quit</span><span class="sh">"</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">"</span><span class="s">Exiting...</span><span class="sh">"</span>
    <span class="k">elif</span> <span class="nf">len</span><span class="p">(</span><span class="n">command</span><span class="p">)</span> <span class="o">==</span> <span class="mi">2</span> <span class="ow">and</span> <span class="n">command</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="sh">"</span><span class="s">load</span><span class="sh">"</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Loading </span><span class="si">{</span><span class="n">command</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="sh">"</span>
    <span class="k">elif</span> <span class="nf">len</span><span class="p">(</span><span class="n">command</span><span class="p">)</span> <span class="o">==</span> <span class="mi">3</span> <span class="ow">and</span> <span class="n">command</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="sh">"</span><span class="s">save</span><span class="sh">"</span><span class="p">:</span>
        <span class="k">return</span> <span class="sa">f</span><span class="sh">"</span><span class="s">Saving </span><span class="si">{</span><span class="n">command</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s"> as </span><span class="si">{</span><span class="n">command</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span><span class="si">}</span><span class="sh">"</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="sh">"</span><span class="s">Unknown command</span><span class="sh">"</span>
</code></pre></div></div> <p><em>Rationale</em>: Pattern matching makes complex conditional logic more readable and maintainable, especially when dealing with structured data.</p> <h4 id="dictionary-merge-and-update-operators---python-39">Dictionary Merge and Update Operators - Python 3.9+</h4> <p>Use <code class="language-plaintext highlighter-rouge">|</code> and <code class="language-plaintext highlighter-rouge">|=</code> operators for merging dictionaries.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Merge dictionaries with | operator
</span><span class="n">defaults</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">color</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">blue</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">size</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">medium</span><span class="sh">"</span><span class="p">}</span>
<span class="n">custom</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">size</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">large</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">style</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">modern</span><span class="sh">"</span><span class="p">}</span>
<span class="n">config</span> <span class="o">=</span> <span class="n">defaults</span> <span class="o">|</span> <span class="n">custom</span>  <span class="c1"># {'color': 'blue', 'size': 'large', 'style': 'modern'}
</span>
<span class="c1"># Update in place with |=
</span><span class="n">settings</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">theme</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">dark</span><span class="sh">"</span><span class="p">}</span>
<span class="n">settings</span> <span class="o">|=</span> <span class="p">{</span><span class="sh">"</span><span class="s">language</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">en</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">theme</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">light</span><span class="sh">"</span><span class="p">}</span>
<span class="c1"># settings is now {'theme': 'light', 'language': 'en'}
</span></code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Old way - more verbose
</span><span class="n">defaults</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">color</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">blue</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">size</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">medium</span><span class="sh">"</span><span class="p">}</span>
<span class="n">custom</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">size</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">large</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">style</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">modern</span><span class="sh">"</span><span class="p">}</span>
<span class="n">config</span> <span class="o">=</span> <span class="p">{</span><span class="o">**</span><span class="n">defaults</span><span class="p">,</span> <span class="o">**</span><span class="n">custom</span><span class="p">}</span>  <span class="c1"># Works but less clear
</span>
<span class="c1"># Or even older
</span><span class="n">config</span> <span class="o">=</span> <span class="n">defaults</span><span class="p">.</span><span class="nf">copy</span><span class="p">()</span>
<span class="n">config</span><span class="p">.</span><span class="nf">update</span><span class="p">(</span><span class="n">custom</span><span class="p">)</span>
</code></pre></div></div> <p><em>Rationale</em>: The <code class="language-plaintext highlighter-rouge">|</code> operator makes dictionary merging more intuitive and consistent with set operations.</p> <h4 id="improved-error-messages---python-310">Improved Error Messages - Python 3.10+</h4> <p>Python 3.10+ provides much more helpful error messages with better context and suggestions.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Example: Better syntax error messages
# Python 3.10+ will point to the exact location and suggest fixes
</span>
<span class="c1"># Missing colon
# if x &gt; 5
#        ^
# SyntaxError: expected ':'
</span>
<span class="c1"># Better name error suggestions
</span><span class="n">name</span> <span class="o">=</span> <span class="sh">"</span><span class="s">Alice</span><span class="sh">"</span>
<span class="c1"># print(nam)
# NameError: name 'nam' is not defined. Did you mean: 'name'?
</span>
<span class="c1"># Better attribute errors
</span><span class="k">class</span> <span class="nc">User</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">username</span> <span class="o">=</span> <span class="sh">"</span><span class="s">alice</span><span class="sh">"</span>

<span class="n">user</span> <span class="o">=</span> <span class="nc">User</span><span class="p">()</span>
<span class="c1"># print(user.usrname)
# AttributeError: 'User' object has no attribute 'usrname'. Did you mean: 'username'?
</span></code></pre></div></div> <h4 id="parenthesized-context-managers---python-310">Parenthesized Context Managers - Python 3.10+</h4> <p>Write cleaner code when using multiple context managers.</p> <p><strong>Yes</strong> (Python 3.10+)</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Parentheses allow natural line breaks
</span><span class="nf">with </span><span class="p">(</span>
    <span class="nf">open</span><span class="p">(</span><span class="sh">"</span><span class="s">input.txt</span><span class="sh">"</span><span class="p">)</span> <span class="k">as</span> <span class="n">infile</span><span class="p">,</span>
    <span class="nf">open</span><span class="p">(</span><span class="sh">"</span><span class="s">output.txt</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">w</span><span class="sh">"</span><span class="p">)</span> <span class="k">as</span> <span class="n">outfile</span><span class="p">,</span>
    <span class="nf">open</span><span class="p">(</span><span class="sh">"</span><span class="s">log.txt</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">w</span><span class="sh">"</span><span class="p">)</span> <span class="k">as</span> <span class="n">logfile</span><span class="p">,</span>
<span class="p">):</span>
    <span class="nf">process_files</span><span class="p">(</span><span class="n">infile</span><span class="p">,</span> <span class="n">outfile</span><span class="p">,</span> <span class="n">logfile</span><span class="p">)</span>
</code></pre></div></div> <p><strong>No</strong> (Python 3.9 and earlier)</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Awkward backslash continuation
</span><span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="sh">"</span><span class="s">input.txt</span><span class="sh">"</span><span class="p">)</span> <span class="k">as</span> <span class="n">infile</span><span class="p">,</span> \
     <span class="nf">open</span><span class="p">(</span><span class="sh">"</span><span class="s">output.txt</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">w</span><span class="sh">"</span><span class="p">)</span> <span class="k">as</span> <span class="n">outfile</span><span class="p">,</span> \
     <span class="nf">open</span><span class="p">(</span><span class="sh">"</span><span class="s">log.txt</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">w</span><span class="sh">"</span><span class="p">)</span> <span class="k">as</span> <span class="n">logfile</span><span class="p">:</span>
    <span class="nf">process_files</span><span class="p">(</span><span class="n">infile</span><span class="p">,</span> <span class="n">outfile</span><span class="p">,</span> <span class="n">logfile</span><span class="p">)</span>
</code></pre></div></div> <p><em>Rationale</em>: Parenthesized context managers improve readability when working with multiple resources.</p> <h3 id="essential-python-idiomatics-and-best-practices">Essential Python Idiomatics and Best Practices</h3> <h4 id="the-if-__name__--__main__-pattern">The <code class="language-plaintext highlighter-rouge">if __name__ == "__main__"</code> Pattern</h4> <p>Use this idiomatic expression to make your Python files both importable modules and executable scripts.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># mymodule.py
</span><span class="k">def</span> <span class="nf">calculate_sum</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Add two numbers.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>

<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
    <span class="sh">"""</span><span class="s">Main entry point when run as script.</span><span class="sh">"""</span>
    <span class="n">result</span> <span class="o">=</span> <span class="nf">calculate_sum</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Result: </span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="sh">"</span><span class="s">__main__</span><span class="sh">"</span><span class="p">:</span>
    <span class="nf">main</span><span class="p">()</span>
</code></pre></div></div> <p><strong>When imported:</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># other_file.py
</span><span class="kn">import</span> <span class="n">mymodule</span>

<span class="c1"># Only the function is available, main() doesn't run automatically
</span><span class="n">result</span> <span class="o">=</span> <span class="n">mymodule</span><span class="p">.</span><span class="nf">calculate_sum</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">20</span><span class="p">)</span>
</code></pre></div></div> <p><strong>When run directly:</strong></p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python mymodule.py  <span class="c"># Runs main() and prints "Result: 8"</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># mymodule.py - Bad practice
</span><span class="k">def</span> <span class="nf">calculate_sum</span><span class="p">(</span><span class="n">a</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="n">b</span><span class="p">:</span> <span class="nb">int</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">int</span><span class="p">:</span>
    <span class="sh">"""</span><span class="s">Add two numbers.</span><span class="sh">"""</span>
    <span class="k">return</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span>

<span class="c1"># Code runs immediately when imported (bad!)
</span><span class="n">result</span> <span class="o">=</span> <span class="nf">calculate_sum</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Result: </span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div> <p><em>Rationale</em>: This pattern allows code reuse. The same file can be used as an importable module or run as a standalone script without executing unwanted side effects during import.</p> <h4 id="logging-vs-print">Logging vs Print</h4> <p>Use the <code class="language-plaintext highlighter-rouge">logging</code> module instead of <code class="language-plaintext highlighter-rouge">print()</code> for anything beyond simple scripts. Logging provides better control over output levels, formatting, and destinations.</p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">logging</span>

<span class="c1"># Configure logging at the start of your application
</span><span class="n">logging</span><span class="p">.</span><span class="nf">basicConfig</span><span class="p">(</span>
    <span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="p">.</span><span class="n">INFO</span><span class="p">,</span>
    <span class="nb">format</span><span class="o">=</span><span class="sh">'</span><span class="s">%(asctime)s - %(name)s - %(levelname)s - %(message)s</span><span class="sh">'</span>
<span class="p">)</span>

<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="p">.</span><span class="nf">getLogger</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">process_data</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
    <span class="n">logger</span><span class="p">.</span><span class="nf">debug</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Processing data: </span><span class="si">{</span><span class="n">data</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">data</span><span class="p">:</span>
        <span class="n">logger</span><span class="p">.</span><span class="nf">warning</span><span class="p">(</span><span class="sh">"</span><span class="s">Empty data received</span><span class="sh">"</span><span class="p">)</span>
        <span class="k">return</span> <span class="bp">None</span>

    <span class="k">try</span><span class="p">:</span>
        <span class="n">result</span> <span class="o">=</span> <span class="nf">expensive_operation</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
        <span class="n">logger</span><span class="p">.</span><span class="nf">info</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Successfully processed </span><span class="si">{</span><span class="nf">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="si">}</span><span class="s"> items</span><span class="sh">"</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">result</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="n">logger</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Failed to process data: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="sh">"</span><span class="p">,</span> <span class="n">exc_info</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
        <span class="k">raise</span>

<span class="c1"># Benefits:
# - Can change log level without modifying code
# - Logs include timestamps and context
# - Can redirect to files, streams, or external services
# - Different loggers for different modules
</span></code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">process_data</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
    <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Processing data: </span><span class="si">{</span><span class="n">data</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>  <span class="c1"># Always prints, no control
</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="n">data</span><span class="p">:</span>
        <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">WARNING: Empty data received</span><span class="sh">"</span><span class="p">)</span>  <span class="c1"># No standard format
</span>        <span class="k">return</span> <span class="bp">None</span>

    <span class="k">try</span><span class="p">:</span>
        <span class="n">result</span> <span class="o">=</span> <span class="nf">expensive_operation</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Processed </span><span class="si">{</span><span class="nf">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="si">}</span><span class="s"> items</span><span class="sh">"</span><span class="p">)</span>  <span class="c1"># Mixed with actual output
</span>        <span class="k">return</span> <span class="n">result</span>
    <span class="k">except</span> <span class="nb">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">ERROR: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>  <span class="c1"># No stack trace, hard to debug
</span>        <span class="k">raise</span>
</code></pre></div></div> <p><strong>Log Levels</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">logging</span>

<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="p">.</span><span class="nf">getLogger</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>

<span class="c1"># Use appropriate levels
</span><span class="n">logger</span><span class="p">.</span><span class="nf">debug</span><span class="p">(</span><span class="sh">"</span><span class="s">Detailed information for debugging</span><span class="sh">"</span><span class="p">)</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">info</span><span class="p">(</span><span class="sh">"</span><span class="s">General informational messages</span><span class="sh">"</span><span class="p">)</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">warning</span><span class="p">(</span><span class="sh">"</span><span class="s">Warning messages for unexpected situations</span><span class="sh">"</span><span class="p">)</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">error</span><span class="p">(</span><span class="sh">"</span><span class="s">Error messages for serious problems</span><span class="sh">"</span><span class="p">)</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">critical</span><span class="p">(</span><span class="sh">"</span><span class="s">Critical messages for very serious errors</span><span class="sh">"</span><span class="p">)</span>

<span class="c1"># In production, set level to INFO or WARNING to reduce noise
</span><span class="n">logging</span><span class="p">.</span><span class="nf">basicConfig</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="p">.</span><span class="n">WARNING</span><span class="p">)</span>
<span class="c1"># Now only warning, error, and critical messages appear
</span></code></pre></div></div> <p><em>Rationale</em>: Logging is configurable, structured, and production-ready. It allows you to control verbosity without changing code and provides better context for debugging.</p> <h4 id="efficient-collection-operations">Efficient Collection Operations</h4> <p>Choose the right data structure for the job. Understanding performance characteristics prevents inefficient code. For more use cases, refer to <a href="https://george-gca.github.io/blog/2023/simple-improvements-python-code/">this blog post</a>.</p> <p><strong>Set Membership Testing</strong></p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Use sets for membership testing - O(1) average case
</span><span class="n">valid_users</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">alice</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">bob</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">charlie</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">david</span><span class="sh">"</span><span class="p">}</span>  <span class="c1"># set
</span>
<span class="k">if</span> <span class="n">username</span> <span class="ow">in</span> <span class="n">valid_users</span><span class="p">:</span>  <span class="c1"># Fast: O(1)
</span>    <span class="nf">grant_access</span><span class="p">()</span>

<span class="c1"># Converting list to set for multiple lookups
</span><span class="n">user_list</span> <span class="o">=</span> <span class="p">[</span><span class="sh">"</span><span class="s">alice</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">bob</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">charlie</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">david</span><span class="sh">"</span><span class="p">]</span>
<span class="n">user_set</span> <span class="o">=</span> <span class="nf">set</span><span class="p">(</span><span class="n">user_list</span><span class="p">)</span>  <span class="c1"># Convert once
</span>
<span class="k">for</span> <span class="n">login_attempt</span> <span class="ow">in</span> <span class="n">login_attempts</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">login_attempt</span> <span class="ow">in</span> <span class="n">user_set</span><span class="p">:</span>  <span class="c1"># O(1) per check
</span>        <span class="nf">process_login</span><span class="p">(</span><span class="n">login_attempt</span><span class="p">)</span>
</code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Using lists for membership testing - O(n) linear search
</span><span class="n">valid_users</span> <span class="o">=</span> <span class="p">[</span><span class="sh">"</span><span class="s">alice</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">bob</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">charlie</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">david</span><span class="sh">"</span><span class="p">]</span>  <span class="c1"># list
</span>
<span class="k">if</span> <span class="n">username</span> <span class="ow">in</span> <span class="n">valid_users</span><span class="p">:</span>  <span class="c1"># Slow: O(n)
</span>    <span class="nf">grant_access</span><span class="p">()</span>

<span class="c1"># Repeatedly searching through lists
</span><span class="k">for</span> <span class="n">login_attempt</span> <span class="ow">in</span> <span class="n">login_attempts</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">login_attempt</span> <span class="ow">in</span> <span class="n">valid_users</span><span class="p">:</span>  <span class="c1"># O(n) per check - very slow!
</span>        <span class="nf">process_login</span><span class="p">(</span><span class="n">login_attempt</span><span class="p">)</span>
</code></pre></div></div> <p><strong>Dictionary for Fast Lookups</strong></p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Use dicts for key-value lookups - O(1)
</span><span class="n">user_scores</span> <span class="o">=</span> <span class="p">{</span>
    <span class="sh">"</span><span class="s">alice</span><span class="sh">"</span><span class="p">:</span> <span class="mi">95</span><span class="p">,</span>
    <span class="sh">"</span><span class="s">bob</span><span class="sh">"</span><span class="p">:</span> <span class="mi">87</span><span class="p">,</span>
    <span class="sh">"</span><span class="s">charlie</span><span class="sh">"</span><span class="p">:</span> <span class="mi">92</span>
<span class="p">}</span>

<span class="n">score</span> <span class="o">=</span> <span class="n">user_scores</span><span class="p">.</span><span class="nf">get</span><span class="p">(</span><span class="sh">"</span><span class="s">alice</span><span class="sh">"</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>  <span class="c1"># Fast lookup with default
</span>
<span class="c1"># Dict comprehension
</span><span class="n">squared</span> <span class="o">=</span> <span class="p">{</span><span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10</span><span class="p">)}</span>
<span class="c1"># {0: 0, 1: 1, 2: 4, 3: 9, ...}
</span></code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Using parallel lists - inefficient and error-prone
</span><span class="n">usernames</span> <span class="o">=</span> <span class="p">[</span><span class="sh">"</span><span class="s">alice</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">bob</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">charlie</span><span class="sh">"</span><span class="p">]</span>
<span class="n">scores</span> <span class="o">=</span> <span class="p">[</span><span class="mi">95</span><span class="p">,</span> <span class="mi">87</span><span class="p">,</span> <span class="mi">92</span><span class="p">]</span>

<span class="c1"># Linear search to find score - O(n)
</span><span class="k">def</span> <span class="nf">get_score</span><span class="p">(</span><span class="n">username</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">name</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">usernames</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">name</span> <span class="o">==</span> <span class="n">username</span><span class="p">:</span>
            <span class="k">return</span> <span class="n">scores</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
    <span class="k">return</span> <span class="mi">0</span>
</code></pre></div></div> <p><strong>Set Operations</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Set operations are fast and readable
</span><span class="n">set_a</span> <span class="o">=</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">}</span>
<span class="n">set_b</span> <span class="o">=</span> <span class="p">{</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">8</span><span class="p">}</span>

<span class="c1"># Union - all unique elements
</span><span class="n">union</span> <span class="o">=</span> <span class="n">set_a</span> <span class="o">|</span> <span class="n">set_b</span>  <span class="c1"># {1, 2, 3, 4, 5, 6, 7, 8}
</span>
<span class="c1"># Intersection - common elements
</span><span class="n">intersection</span> <span class="o">=</span> <span class="n">set_a</span> <span class="o">&amp;</span> <span class="n">set_b</span>  <span class="c1"># {4, 5}
</span>
<span class="c1"># Difference - elements in a but not in b
</span><span class="n">difference</span> <span class="o">=</span> <span class="n">set_a</span> <span class="o">-</span> <span class="n">set_b</span>  <span class="c1"># {1, 2, 3}
</span>
<span class="c1"># Symmetric difference - elements in either but not both
</span><span class="n">sym_diff</span> <span class="o">=</span> <span class="n">set_a</span> <span class="o">^</span> <span class="n">set_b</span>  <span class="c1"># {1, 2, 3, 6, 7, 8}
</span>
<span class="c1"># Remove duplicates from a list
</span><span class="n">unique_items</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">set</span><span class="p">(</span><span class="n">items_with_duplicates</span><span class="p">))</span>
</code></pre></div></div> <p><strong>List vs Generator for Large Data</strong></p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Generator - memory efficient for large data
</span><span class="k">def</span> <span class="nf">read_large_file</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
    <span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">f</span><span class="p">:</span>  <span class="c1"># Processes one line at a time
</span>            <span class="k">yield</span> <span class="n">line</span><span class="p">.</span><span class="nf">strip</span><span class="p">()</span>

<span class="c1"># Only loads one line at a time
</span><span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="nf">read_large_file</span><span class="p">(</span><span class="sh">"</span><span class="s">huge_file.txt</span><span class="sh">"</span><span class="p">):</span>
    <span class="nf">process</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>

<span class="c1"># Generator expression
</span><span class="n">sum_of_squares</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">1000000</span><span class="p">))</span>  <span class="c1"># Memory efficient
</span></code></pre></div></div> <p><strong>No</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># List - loads everything into memory
</span><span class="k">def</span> <span class="nf">read_large_file</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span>
    <span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="k">return</span> <span class="p">[</span><span class="n">line</span><span class="p">.</span><span class="nf">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">f</span><span class="p">]</span>  <span class="c1"># Loads entire file!
</span>
<span class="c1"># Memory intensive
</span><span class="n">all_lines</span> <span class="o">=</span> <span class="nf">read_large_file</span><span class="p">(</span><span class="sh">"</span><span class="s">huge_file.txt</span><span class="sh">"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">all_lines</span><span class="p">:</span>
    <span class="nf">process</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>

<span class="c1"># List comprehension - creates full list in memory
</span><span class="n">sum_of_squares</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">([</span><span class="n">x</span><span class="o">**</span><span class="mi">2</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">1000000</span><span class="p">)])</span>  <span class="c1"># Wasteful
</span></code></pre></div></div> <p><em>Rationale</em>: Using the right data structure improves performance dramatically. Sets and dicts offer O(1) lookups, while lists require O(n) searches. Generators save memory for large datasets.</p> <h4 id="duck-typing-and-eafp-vs-lbyl">Duck Typing and EAFP vs LBYL</h4> <p>Duck typing is a programming concept where the type or class of an object is determined by its behavior (methods and properties), rather than its explicit inheritance or type. The phrase “If it walks like a duck and quacks like a duck, it’s a duck” means that if an object implements the necessary methods or behaviors, it can be used wherever those behaviors are expected—regardless of its actual type. This approach makes code more flexible and reusable, as it focuses on what an object can do, not what it is. Python also follows the philosophy of “Easier to Ask for Forgiveness than Permission” (EAFP) rather than “Look Before You Leap” (LBYL).</p> <p><strong>EAFP - Pythonic Approach</strong></p> <p><strong>Yes</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># EAFP: Try the operation, handle exceptions if it fails
</span><span class="k">def</span> <span class="nf">get_user_age</span><span class="p">(</span><span class="n">user_dict</span><span class="p">):</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">user_dict</span><span class="p">[</span><span class="sh">"</span><span class="s">age</span><span class="sh">"</span><span class="p">]</span>
    <span class="k">except</span> <span class="nb">KeyError</span><span class="p">:</span>
        <span class="k">return</span> <span class="bp">None</span>

<span class="c1"># Duck typing: "If it walks like a duck and quacks like a duck..."
</span><span class="k">def</span> <span class="nf">process_file</span><span class="p">(</span><span class="n">file_obj</span><span class="p">):</span>
    <span class="c1"># Don't check type - just use it like a file
</span>    <span class="k">try</span><span class="p">:</span>
        <span class="n">content</span> <span class="o">=</span> <span class="n">file_obj</span><span class="p">.</span><span class="nf">read</span><span class="p">()</span>
        <span class="k">return</span> <span class="n">content</span><span class="p">.</span><span class="nf">upper</span><span class="p">()</span>
    <span class="k">except</span> <span class="nb">AttributeError</span><span class="p">:</span>
        <span class="k">raise</span> <span class="nc">TypeError</span><span class="p">(</span><span class="sh">"</span><span class="s">Object must have a read() method</span><span class="sh">"</span><span class="p">)</span>

<span class="c1"># Works with any file-like object
</span><span class="kn">from</span> <span class="n">io</span> <span class="kn">import</span> <span class="n">StringIO</span>
<span class="nf">process_file</span><span class="p">(</span><span class="nf">open</span><span class="p">(</span><span class="sh">"</span><span class="s">file.txt</span><span class="sh">"</span><span class="p">))</span>  <span class="c1"># Real file
</span><span class="nf">process_file</span><span class="p">(</span><span class="nc">StringIO</span><span class="p">(</span><span class="sh">"</span><span class="s">test</span><span class="sh">"</span><span class="p">))</span>  <span class="c1"># String buffer - also works!
</span>
<span class="c1"># EAFP with dict access
</span><span class="n">config</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">timeout</span><span class="sh">"</span><span class="p">:</span> <span class="mi">30</span><span class="p">,</span> <span class="sh">"</span><span class="s">retries</span><span class="sh">"</span><span class="p">:</span> <span class="mi">3</span><span class="p">}</span>
<span class="k">try</span><span class="p">:</span>
    <span class="n">timeout</span> <span class="o">=</span> <span class="n">config</span><span class="p">[</span><span class="sh">"</span><span class="s">timeout</span><span class="sh">"</span><span class="p">]</span>
    <span class="n">retries</span> <span class="o">=</span> <span class="n">config</span><span class="p">[</span><span class="sh">"</span><span class="s">retries</span><span class="sh">"</span><span class="p">]</span>
<span class="k">except</span> <span class="nb">KeyError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
    <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">Missing required config: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div> <p><strong>No - LBYL (Look Before You Leap)</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># LBYL: Check before you try (less Pythonic, race conditions)
</span><span class="k">def</span> <span class="nf">get_user_age</span><span class="p">(</span><span class="n">user_dict</span><span class="p">):</span>
    <span class="k">if</span> <span class="sh">"</span><span class="s">age</span><span class="sh">"</span> <span class="ow">in</span> <span class="n">user_dict</span><span class="p">:</span>  <span class="c1"># Extra check
</span>        <span class="k">return</span> <span class="n">user_dict</span><span class="p">[</span><span class="sh">"</span><span class="s">age</span><span class="sh">"</span><span class="p">]</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">return</span> <span class="bp">None</span>

<span class="c1"># Type checking instead of duck typing (rigid)
</span><span class="k">def</span> <span class="nf">process_file</span><span class="p">(</span><span class="n">file_obj</span><span class="p">):</span>
    <span class="k">if</span> <span class="ow">not</span> <span class="nf">isinstance</span><span class="p">(</span><span class="n">file_obj</span><span class="p">,</span> <span class="n">io</span><span class="p">.</span><span class="n">IOBase</span><span class="p">):</span>  <span class="c1"># Too restrictive!
</span>        <span class="k">raise</span> <span class="nc">TypeError</span><span class="p">(</span><span class="sh">"</span><span class="s">Must be a file object</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">content</span> <span class="o">=</span> <span class="n">file_obj</span><span class="p">.</span><span class="nf">read</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">content</span><span class="p">.</span><span class="nf">upper</span><span class="p">()</span>
<span class="c1"># Now StringIO won't work, even though it has read()!
</span>
<span class="c1"># Multiple checks (verbose and slower)
</span><span class="n">config</span> <span class="o">=</span> <span class="p">{</span><span class="sh">"</span><span class="s">timeout</span><span class="sh">"</span><span class="p">:</span> <span class="mi">30</span><span class="p">,</span> <span class="sh">"</span><span class="s">retries</span><span class="sh">"</span><span class="p">:</span> <span class="mi">3</span><span class="p">}</span>
<span class="k">if</span> <span class="sh">"</span><span class="s">timeout</span><span class="sh">"</span> <span class="ow">in</span> <span class="n">config</span> <span class="ow">and</span> <span class="sh">"</span><span class="s">retries</span><span class="sh">"</span> <span class="ow">in</span> <span class="n">config</span><span class="p">:</span>
    <span class="n">timeout</span> <span class="o">=</span> <span class="n">config</span><span class="p">[</span><span class="sh">"</span><span class="s">timeout</span><span class="sh">"</span><span class="p">]</span>
    <span class="n">retries</span> <span class="o">=</span> <span class="n">config</span><span class="p">[</span><span class="sh">"</span><span class="s">retries</span><span class="sh">"</span><span class="p">]</span>
<span class="k">else</span><span class="p">:</span>
    <span class="k">raise</span> <span class="nc">ValueError</span><span class="p">(</span><span class="sh">"</span><span class="s">Missing required config</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div> <p><strong>More EAFP Examples</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Converting to int
# EAFP - Pythonic
</span><span class="k">try</span><span class="p">:</span>
    <span class="n">value</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="n">user_input</span><span class="p">)</span>
<span class="k">except</span> <span class="nb">ValueError</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Invalid number</span><span class="sh">"</span><span class="p">)</span>

<span class="c1"># LBYL - Not Pythonic
</span><span class="k">if</span> <span class="n">user_input</span><span class="p">.</span><span class="nf">isdigit</span><span class="p">():</span>
    <span class="n">value</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="n">user_input</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Invalid number</span><span class="sh">"</span><span class="p">)</span>
<span class="c1"># Problem: isdigit() doesn't handle negative numbers or floats
</span>
<span class="c1"># File operations
# EAFP - Pythonic
</span><span class="k">try</span><span class="p">:</span>
    <span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="sh">"</span><span class="s">config.json</span><span class="sh">"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">config</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
<span class="k">except</span> <span class="nb">FileNotFoundError</span><span class="p">:</span>
    <span class="n">config</span> <span class="o">=</span> <span class="nf">default_config</span><span class="p">()</span>
<span class="k">except</span> <span class="n">json</span><span class="p">.</span><span class="n">JSONDecodeError</span><span class="p">:</span>
    <span class="nf">print</span><span class="p">(</span><span class="sh">"</span><span class="s">Invalid JSON</span><span class="sh">"</span><span class="p">)</span>

<span class="c1"># LBYL - Less Pythonic
</span><span class="kn">import</span> <span class="n">os</span>
<span class="k">if</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="nf">exists</span><span class="p">(</span><span class="sh">"</span><span class="s">config.json</span><span class="sh">"</span><span class="p">):</span>
    <span class="c1"># Race condition: file could be deleted between check and open!
</span>    <span class="k">with</span> <span class="nf">open</span><span class="p">(</span><span class="sh">"</span><span class="s">config.json</span><span class="sh">"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
        <span class="n">config</span> <span class="o">=</span> <span class="n">json</span><span class="p">.</span><span class="nf">load</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
    <span class="n">config</span> <span class="o">=</span> <span class="nf">default_config</span><span class="p">()</span>
</code></pre></div></div> <p><strong>Duck Typing Benefits</strong></p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Functions work with any compatible type
</span><span class="k">def</span> <span class="nf">print_all</span><span class="p">(</span><span class="n">items</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Works with lists, tuples, sets, generators, etc.</span><span class="sh">"""</span>
    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">:</span>  <span class="c1"># Just needs to be iterable
</span>        <span class="nf">print</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>

<span class="nf">print_all</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">])</span>           <span class="c1"># list
</span><span class="nf">print_all</span><span class="p">((</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span>           <span class="c1"># tuple
</span><span class="nf">print_all</span><span class="p">({</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">})</span>           <span class="c1"># set
</span><span class="nf">print_all</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">))</span>         <span class="c1"># range object
</span><span class="nf">print_all</span><span class="p">(</span><span class="n">x</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">])</span>  <span class="c1"># generator
</span>
<span class="c1"># Custom class works too if it implements __iter__
</span><span class="k">class</span> <span class="nc">MyCollection</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">data</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">data</span> <span class="o">=</span> <span class="n">data</span>

    <span class="k">def</span> <span class="nf">__iter__</span><span class="p">(</span><span class="n">self</span><span class="p">):</span>
        <span class="k">return</span> <span class="nf">iter</span><span class="p">(</span><span class="n">self</span><span class="p">.</span><span class="n">data</span><span class="p">)</span>

<span class="nf">print_all</span><span class="p">(</span><span class="nc">MyCollection</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">]))</span>  <span class="c1"># Works!
</span></code></pre></div></div> <p><em>Rationale</em>: EAFP is more Pythonic, often faster (one operation vs check + operation), and handles edge cases better. Duck typing makes code more flexible and reusable by focusing on behavior rather than type.</p>]]></content><author><name></name></author><category term="python"/><category term="programming"/><category term="code"/><category term="improvement"/><category term="python"/><summary type="html"><![CDATA[From code style and modern features to leveraging the standard library and essential idioms for writing clean, efficient Python code.]]></summary></entry><entry><title type="html">Analyzing the history of CVPR</title><link href="https://george-gca.github.io/blog/2025/cvpr-history-analysis/" rel="alternate" type="text/html" title="Analyzing the history of CVPR"/><published>2025-04-25T16:43:13+00:00</published><updated>2025-04-25T16:43:13+00:00</updated><id>https://george-gca.github.io/blog/2025/cvpr-history-analysis</id><content type="html" xml:base="https://george-gca.github.io/blog/2025/cvpr-history-analysis/"><![CDATA[<p>As the <a href="https://cvpr.thecvf.com/">IEEE/CVF Conference on Computer Vision and Pattern Recognition</a> (CVPR) 2025 approaches, let’s take a look at the history of the conference and its workshops from 2017 to 2024. The goal of this analysis is to provide insights into the evolution of topics and trends in artificial intelligence research over the years. Keep in mind that this information should be taken with a grain of salt, as some of the information that may be relevant to the analyses is discarded during the cleaning process. Some of the analysis is based on keywords, and we make some assumptions about how authors use keywords (e.g. it’s pretty unlikely that a paper about image data would have the keyword <code class="language-plaintext highlighter-rouge">audio</code> in its title or abstract), but this is not a perfect solution. The goal of this post is to give some insight into the history of the conference, not to be a definitive analysis.</p> <p>Note that some of the graphs use percentiles of the total number of papers published in each year. Since there are different numbers of papers published each year, you can’t really compare the numbers from one year to the next. The goal of these graphs is to show the distribution of papers published during the period and any changes in the focus of the academic community. You can also interact with the visualizations here. You can zoom in on specific parts, enable or disable lines by clicking on their names in the legend, and hover over the points to see more information.</p> <h2 id="overall-statistics">Overall Statistics</h2> <p>Here you can see the number of published papers. Each year, there are more and more papers published compared to the previous year, except for 2023. There were more than three times as many papers published in 2024 as in 2017.</p> <pre><code class="language-plotly">{"data": [{"hovertemplate": "year=%{x}&lt;br&gt;papers=%{y}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "", "orientation": "v", "showlegend": false, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "i2", "bdata": "KAQuBVQHwQd+CEgKNgmgDQ=="}, "yaxis": "y", "type": "scatter"}], "layout": {"xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "year"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "papers"}}, "legend": {"tracegroupgap": 0}}}
</code></pre> <p>Regarding the modalities used in the papers, we can see that image is still the most common, but the use of text and multiple modalities has increased significantly. The application of optical flow, graphs and depth information has decreased in the last years, while the use of particles has remained relatively stable.</p> <pre><code class="language-plotly">{"data": [{"customdata": [["audio"], ["audio"], ["audio"], ["audio"], ["audio"], ["audio"], ["audio"], ["audio"]], "hovertemplate": "modality=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "audio", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "audio", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "2FBeQ3kN5T8dk/Uck/XsP30vhdy8DuE/g0lGn20u6D/N5tSIhffrP/WdjfrORvU/WASE4EIk+z+P78JB9PgAQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["depth"], ["depth"], ["depth"], ["depth"], ["depth"], ["depth"], ["depth"], ["depth"]], "hovertemplate": "modality=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "depth", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "depth", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "zB4we8DsE0Ak1egj1egTQER0/3wvhRhAQj1lr7AmFEDHDwNNB98TQMTkCmJyBRFAzGK7c/F4EUDBpv1kCWwPQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["graph"], ["graph"], ["graph"], ["graph"], ["graph"], ["graph"], ["graph"], ["graph"]], "hovertemplate": "modality=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "graph", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "graph", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "HX1z9M3RC0A+eSo+eSoOQHumE2xSRRFAg0lGn20uGEDucuibFmAQQL+zUd/ZqAtALkSykbMfCkCWwKb9ZAkDQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["image"], ["image"], ["image"], ["image"], ["image"], ["image"], ["image"], ["image"]], "hovertemplate": "modality=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "image", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "image", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "eQ3lNZQXQkBUyixUyixCQAEGofVGhkBAMA4SdHz7PkB3eggk2Ro8QPeySqCiNz1AeiSI92T9O0B8Fw6ixydAQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["mesh"], ["mesh"], ["mesh"], ["mesh"], ["mesh"], ["mesh"], ["mesh"], ["mesh"]], "hovertemplate": "modality=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "mesh", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "mesh", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP6D/bxovaxovqP0kPVM5u4fc/kOUMnMb8+D9dS0BRmUsBQCZXEJMriPk/XoOZB+cIBUCUJbBpP1kCQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["multi modal"], ["multi modal"], ["multi modal"], ["multi modal"], ["multi modal"], ["multi modal"], ["multi modal"], ["multi modal"]], "hovertemplate": "modality=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "multi modal", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "multi modal", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "FbFUxFIRC0A1SIM0SIMEQFJF/XDtmQZAw1Unjyo2DEDlDfuqVnANQCdeT8ocAxhA1CNBvCfrF0DtJ0tg034jQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["optical flow"], ["optical flow"], ["optical flow"], ["optical flow"], ["optical flow"], ["optical flow"], ["optical flow"], ["optical flow"]], "hovertemplate": "modality=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "optical flow", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "optical flow", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "yLgg44KMA0A+eSo+eSr+Pw7LXP52jv8/98VBgo5v/z+EcWIiEo33P1osjwhNtfc/JoMsSX2t8z8Vc6szUjHvPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["particle"], ["particle"], ["particle"], ["particle"], ["particle"], ["particle"], ["particle"], ["particle"]], "hovertemplate": "modality=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "particle", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "particle", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPyD8TYk4TYk6zPy5/O8fHSrs/AjGEv/Me0D8j1cmZzanRPylzDHDwc9M/mwIc7fRIwD84iB7fhYPQPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["path"], ["path"], ["path"], ["path"], ["path"], ["path"], ["path"], ["path"]], "hovertemplate": "modality=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "path", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "path", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "NOHPhD8T7j+Y+iGY+iH4P4RTS55mNABAg0lGn20u+D+cmIhE4wX5P1osjwhNtfc/QgNjKDJb9D9GKuZWZ6T0Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["point cloud"], ["point cloud"], ["point cloud"], ["point cloud"], ["point cloud"], ["point cloud"], ["point cloud"], ["point cloud"]], "hovertemplate": "modality=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "point cloud", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "point cloud", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "FbFUxFIR6z8D77MC77MCQFlpwzKXvwVAw1Unjyo2DED9NCHNJ+kOQCVQ0Vs6DQtAA2MoMlvUEkCpmFudkYoIQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["text"], ["text"], ["text"], ["text"], ["text"], ["text"], ["text"], ["text"]], "hovertemplate": "modality=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "text", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "text", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPGEB3FO12FO0WQD/ZqivwKBlAU4Bd658oFUBUIxbeb5sUQChljgEOfhZAQgNjKDJbFEAJbNpPlsAbQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["video"], ["video"], ["video"], ["video"], ["video"], ["video"], ["video"], ["video"]], "hovertemplate": "modality=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "video", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "video", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "NpTXUF5DLkCE5g2E5g0sQMnTjAYkxidAjT7bXDDJKEDsq1rBdfQqQL+zUd/ZqCtANeR/ySBLKkDYtJ8sgc0pQA=="}, "yaxis": "y", "type": "scatter"}], "layout": {"legend": {"title": {"text": "modality"}, "tracegroupgap": 0}, "xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "year"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "occurrences (%)"}}}}
</code></pre> <p>It is quite common for papers to introduce new concepts, be it a new method, a new dataset, or a new architecture. The following graph shows the most common concepts introduced in the papers. Not surprisingly, algorithms are the most common concept. Algorithms also involve new methods or approaches. Novel tasks have also been introduced over the years, which is highly correlated with the creation of novel datasets. The introduction of new architectures has also increased in the last year, including new models, modules, and networks. The creation of different losses and metrics has been quite stable over the years, with very few papers introducing new ones.</p> <pre><code class="language-plotly">{"data": [{"customdata": [["algorithms"], ["algorithms"], ["algorithms"], ["algorithms"], ["algorithms"], ["algorithms"], ["algorithms"], ["algorithms"]], "hovertemplate": "concept=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "algorithms", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "algorithms", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "qYilIpaKAEA+eSo+eSr+P1x7phNsUgVA3Y20iNzS/T9UIxbeb5v0P1osjwhNtfc/GoUB+zTk/z+P78JB9PgQQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["architectures"], ["architectures"], ["architectures"], ["architectures"], ["architectures"], ["architectures"], ["architectures"], ["architectures"]], "hovertemplate": "concept=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "architectures", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "architectures", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "2FBeQ3kN5T9fX19fX1/vP4RTS55mNPA/0PHti4ME7T+XwbYIZe3wPylzDHDwc/M//gTLG4A27z8H0eO7cBD7Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["datasets"], ["datasets"], ["datasets"], ["datasets"], ["datasets"], ["datasets"], ["datasets"], ["datasets"]], "hovertemplate": "concept=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "datasets", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "datasets", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "5+ibo2+O9j/8rMD7rMD7PyE3r0N0//w/g0lGn20u+D87/O+7niLzP4rXkzLHAP8/44SUPMuI/j9s2k+WwKb/Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["losses"], ["losses"], ["losses"], ["losses"], ["losses"], ["losses"], ["losses"], ["losses"]], "hovertemplate": "concept=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "losses", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "losses", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPuD8dk/Uck/XcP30vhdy8DtE/aRG5pbuR1j+1v65mtH7aP76sEqjoLc0/WASE4EIkyz9LYNN+sgTGPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["metrics"], ["metrics"], ["metrics"], ["metrics"], ["metrics"], ["metrics"], ["metrics"], ["metrics"]], "hovertemplate": "concept=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "metrics", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "metrics", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAATYk4TYk6zPy5/O8fHSqs/nYHTmB/LuT/lDfuqVnDNPwAAAAAAAAAAeQPQ5pu2pT+61RmpmFu9Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["tasks"], ["tasks"], ["tasks"], ["tasks"], ["tasks"], ["tasks"], ["tasks"], ["tasks"]], "hovertemplate": "concept=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "tasks", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "tasks", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP2D8TYk4TYk7TPxTvIsAgtO4/0PHti4ME7T9sSjwAQRTmP1w6DXcvq/Q/XoOZB+cI9T9GKuZWZ6T0Pw=="}, "yaxis": "y", "type": "scatter"}], "layout": {"xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "year"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "occurrences (%)"}}, "legend": {"title": {"text": "concept"}, "tracegroupgap": 0}}}
</code></pre> <p>Regarding the common tasks in the papers, we can see a steep increase in generation tasks, especially after 2022. This may be related to the advances in large language models such as <a href="https://openreview.net/forum?id=TG8KACxEON">InstructGPT</a> and <a href="https://openai.com/index/chatgpt/">ChatGPT</a> by the end of 2022, and the release of the first collections of foundational language models such as <a href="https://arxiv.org/abs/2302.13971">LLaMA</a> in early 2023. Classification, detection, estimation, and recognition have seen a decline in interest over the years, while prediction has only recently seen a decrease. Tasks such as segmentation have remained relatively stable. The use of reasoning tasks has also increased significantly in the last year, but is still a small percentage of the total number of published papers (about 3%).</p> <pre><code class="language-plotly">{"data": [{"customdata": [["captioning"], ["captioning"], ["captioning"], ["captioning"], ["captioning"], ["captioning"], ["captioning"], ["captioning"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "captioning", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "captioning", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "JUmSJEmS/D/yexnyexnyP3YLvxoT6fE/T9krrAn15D9UIxbeb5vkP76sEqjoLe0/mwIc7fRI8D/5LhxEj+/2Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["classification"], ["classification"], ["classification"], ["classification"], ["classification"], ["classification"], ["classification"], ["classification"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "classification", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "classification", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "zB4we8DsI0CmpaWlpaUhQPI0owGJcSJAlEcVG646IUCng+85dnYfQL+zUd/ZqBtAzYNzhLq/F0DMrc5IxVwWQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["clustering"], ["clustering"], ["clustering"], ["clustering"], ["clustering"], ["clustering"], ["clustering"], ["clustering"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "clustering", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "clustering", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "qYilIpaKAED8rMD7rMD7P4RTS55mNABAIrd0N9IiAkDRNy3AMI8AQF1Ii+URoQFA/gTLG4A2/z9VzK3OSMX4Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["counting"], ["counting"], ["counting"], ["counting"], ["counting"], ["counting"], ["counting"], ["counting"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "counting", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "counting", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "2FBeQ3kN5T9WLrhVLrjlP1x7phNsUvU/0PHti4ME7T9sSjwAQRTmP44BDn5u4uU/6QOqY29t2D8Vc6szUjHfPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["detection"], ["detection"], ["detection"], ["detection"], ["detection"], ["detection"], ["detection"], ["detection"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "detection", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "detection", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "DDIuyLggKkCIh4eHh4cnQMOvxkR6oChAFWDX+idKKUCJhffbJuUlQNuvLqTF8iZAA2MoMlvUIkB/sgQ27WciQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["estimation"], ["estimation"], ["estimation"], ["estimation"], ["estimation"], ["estimation"], ["estimation"], ["estimation"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "estimation", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "estimation", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "vzn65uibIkA/Uo0+Uo0iQBycWvI0ox1AEnR8++IgIUAfhHFiIhIdQCZXEJMriBlAPIRNAY52GkD7yRLYtJ8XQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["forecasting"], ["forecasting"], ["forecasting"], ["forecasting"], ["forecasting"], ["forecasting"], ["forecasting"], ["forecasting"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "forecasting", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "forecasting", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP2D8TYk4TYk7TP0kPVM5u4dc/g0lGn20u6D87/O+7niLjP/BzE68nZe4/0wKJq16k4T8Cm/aTJbDpPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["generation"], ["generation"], ["generation"], ["generation"], ["generation"], ["generation"], ["generation"], ["generation"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "generation", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "generation", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "+ubom6NvGECEv3CEv3AgQHumE2xSRSFAzgWTjD7bJEBNhbbHUBcnQPSPD4zsUChAtRpffs7rMECuzkjF3Mo2QA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["identification"], ["identification"], ["identification"], ["identification"], ["identification"], ["identification"], ["identification"], ["identification"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "identification", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "identification", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "wOwBswfMAkAMIFsMIFsMQDWjAYlxcApAQj1lr7AmBEA7/O+7niIDQPKBkR0KW/s/WASE4EIk6z9LYNN+sgT2Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["navigation"], ["navigation"], ["navigation"], ["navigation"], ["navigation"], ["navigation"], ["navigation"], ["navigation"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "navigation", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "navigation", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP6D93FO12FO32P0kPVM5u4fc/trlgktFn6z/HDwNNB9/zPylzDHDwc/M/7oK/ihNS8j+ix3fhIHr2Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["prediction"], ["prediction"], ["prediction"], ["prediction"], ["prediction"], ["prediction"], ["prediction"], ["prediction"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "prediction", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "prediction", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "tbrT6k6rIUAdbFgdbFghQOBRwiz2ySRA6+RRxYarJkA7/O+7niIjQEFMriAmVyZA76N3m9yYKEDDQfT4LpwjQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["reasoning"], ["reasoning"], ["reasoning"], ["reasoning"], ["reasoning"], ["reasoning"], ["reasoning"], ["reasoning"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "reasoning", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "reasoning", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "2FBeQ3kNBUAk1egj1egDQFJF/XDtmQZAfPviIEHHB0DWDv/7rqcIQMPWjPOPDwRAJoMsSX2tA0AJbNpPlsALQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["recognition"], ["recognition"], ["recognition"], ["recognition"], ["recognition"], ["recognition"], ["recognition"], ["recognition"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "recognition", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "recognition", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "2FBeQ3kNJUCmpaWlpaUhQCbSA5WzWxxAumCS0WebG0D4XU+RqdAWQPSPD4zsUBhAQgNjKDJbFEBlCWzaTxYRQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["regression"], ["regression"], ["regression"], ["regression"], ["regression"], ["regression"], ["regression"], ["regression"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "regression", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "regression", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "LBWxVMRSDUAk1egj1egDQHDn+FhpwwJAKQXYtf6JAkAj1cmZzakBQPakzDHAwQNAQgNjKDJb9D+n/WQJbNr3Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["retrieval"], ["retrieval"], ["retrieval"], ["retrieval"], ["retrieval"], ["retrieval"], ["retrieval"], ["retrieval"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "retrieval", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "retrieval", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "DeU1lNdQCkBWLrhVLrgFQFJF/XDtmQZAL1M7NCvxAkAQhXWzekkIQFszzj8+MAZASsTocGjNCkDyXTiIHt8EQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["segmentation"], ["segmentation"], ["segmentation"], ["segmentation"], ["segmentation"], ["segmentation"], ["segmentation"], ["segmentation"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "segmentation", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "segmentation", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "MHvA7AGzHUDRleTQleQgQAOPEmaxTyBAgF3rnygFIECrl4Tzis4dQF5PyhwDHCBAmwIc7fRIIEDPSMXc6swgQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["tracking"], ["tracking"], ["tracking"], ["tracking"], ["tracking"], ["tracking"], ["tracking"], ["tracking"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "tracking", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "tracking", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "0IQ/E/5MFEBJXJdIXJcQQChbdQUeJQxAtrlgktFnC0DucuibFmAQQCVQ0Vs6DQtAQgNjKDJbBEAFNu0nS2AKQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["translation"], ["translation"], ["translation"], ["translation"], ["translation"], ["translation"], ["translation"], ["translation"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "translation", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "translation", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "FbFUxFIR6z8TYk4TYk4DQFJF/XDtmQZAPO8BMYS/A0BUIxbeb5sEQJEWyyNCUwFAlYMGxlBk9j+ZW52RirnzPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["verification"], ["verification"], ["verification"], ["verification"], ["verification"], ["verification"], ["verification"], ["verification"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "verification", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "verification", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "FbFUxFIR6z8dk/Uck/XsPxTvIsAgtO4/g0lGn20u6D+EcWIiEo3XP/SPD4zsUNg/eQPQ5pu21T84iB7fhYPQPw=="}, "yaxis": "y", "type": "scatter"}], "layout": {"xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "year"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "occurrences (%)"}}, "legend": {"title": {"text": "task"}, "tracegroupgap": 0}}}
</code></pre> <p>Let’s dive a little deeper into the tasks.</p> <p>Algorithms focused on <strong>security and privacy</strong> have been around for a while, but the number of papers published on them has increased significantly in the last year. Spoofing detection is crucial for applications such as identity recognition, where attackers may try to use photos or videos to impersonate someone else, and has seemed to gain urgency since deepfake technologies have become more prevalent.</p> <pre><code class="language-plotly">{"data": [{"customdata": [["adversarial attack"], ["adversarial attack"], ["adversarial attack"], ["adversarial attack"], ["adversarial attack"], ["adversarial attack"], ["adversarial attack"], ["adversarial attack"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "adversarial attack", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "adversarial attack", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPuD8dk/Uck/XcP1ZX4FHCLPY/D81KvEztAEBUIxbeb5v0P8HIDoWtGfc/BITgQiQb+T/5LhxEj+/2Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["anomaly detection"], ["anomaly detection"], ["anomaly detection"], ["anomaly detection"], ["anomaly detection"], ["anomaly detection"], ["anomaly detection"], ["anomaly detection"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "anomaly detection", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "anomaly detection", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPyD8TYk4TYk7jP3Dn+Fhpw+I/aRG5pbuR5j8j1cmZzanhPylzDHDwc+M/mwIc7fRI4D8Vc6szUjHvPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["disambiguation"], ["disambiguation"], ["disambiguation"], ["disambiguation"], ["disambiguation"], ["disambiguation"], ["disambiguation"], ["disambiguation"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "disambiguation", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "disambiguation", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPuD8AAAAAAAAAAC5/O8fHSrs/AAAAAAAAAACEcWIiEo2nPylzDHDwc6M/mwIc7fRIwD+UJbBpP1nCPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["face verification"], ["face verification"], ["face verification"], ["face verification"], ["face verification"], ["face verification"], ["face verification"], ["face verification"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "face verification", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "face verification", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP2D9WLrhVLrjlPy5/O8fHSts/NqGesldYwz+EcWIiEo23P76sEqjoLb0/eQPQ5pu2pT+61RmpmFudPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["fact checking"], ["fact checking"], ["fact checking"], ["fact checking"], ["fact checking"], ["fact checking"], ["fact checking"], ["fact checking"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "fact checking", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "fact checking", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAClzDHDwc6M/AAAAAAAAAAAAAAAAAAAAAA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["forensics"], ["forensics"], ["forensics"], ["forensics"], ["forensics"], ["forensics"], ["forensics"], ["forensics"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "forensics", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "forensics", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "FbFUxFIR6z+Y+iGY+iHYP2OfbNUVeOQ/T9krrAn15D87/O+7niLjP/SPD4zsUNg/WASE4EIkyz8Cm/aTJbDZPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["fraud detection"], ["fraud detection"], ["fraud detection"], ["fraud detection"], ["fraud detection"], ["fraud detection"], ["fraud detection"], ["fraud detection"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "fraud detection", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "fraud detection", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnYHTmB/LqT8AAAAAAAAAAClzDHDwc7M/eQPQ5pu2pT+61RmpmFu9Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["privacy"], ["privacy"], ["privacy"], ["privacy"], ["privacy"], ["privacy"], ["privacy"], ["privacy"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "privacy", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "privacy", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP6D8dk/Uck/XcPxTvIsAgtO4/0PHti4ME7T+XwbYIZe3wP8HIDoWtGfc/IAQXItnI+T+waT9ZApv6Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["safety"], ["safety"], ["safety"], ["safety"], ["safety"], ["safety"], ["safety"], ["safety"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "safety", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "safety", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "2FBeQ3kN9T8TYk4TYk7zP3Dn+FhpwwJAaRG5pbuR9j+cmIhE4wX5P11Ii+URoQFAjwTxnqx//D/yXTiIHt8EQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["spamming"], ["spamming"], ["spamming"], ["spamming"], ["spamming"], ["spamming"], ["spamming"], ["spamming"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "spamming", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "spamming", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAClzDHDwc6M/AAAAAAAAAAC61RmpmFudPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["spoofing"], ["spoofing"], ["spoofing"], ["spoofing"], ["spoofing"], ["spoofing"], ["spoofing"], ["spoofing"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "spoofing", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "spoofing", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPuD8TYk4TYk7TP30vhdy8DuE/nYHTmB/L2T8j1cmZzanBP/SPD4zsUMg/eQPQ5pu2xT84iB7fhYPgPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["spotting"], ["spotting"], ["spotting"], ["spotting"], ["spotting"], ["spotting"], ["spotting"], ["spotting"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "spotting", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "spotting", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP2D8dk/Uck/XcP2OfbNUVeMQ/0PHti4ME3T8j1cmZzanRP/SPD4zsUMg/eQPQ5pu2xT+UJbBpP1nCPw=="}, "yaxis": "y", "type": "scatter"}], "layout": {"xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "year"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "occurrences (%)"}}, "legend": {"title": {"text": "task"}, "tracegroupgap": 0}}}
</code></pre> <p><strong>Explainability and interpretability</strong> has gained traction in the last few years, with a significant increase in the number of papers published on the topic around 2019, following a surge in some specific conferences and workshops on model transparency, interpretability, and fairness, such as <a href="https://facctconference.org/">ACM FaccT</a> and <a href="https://visxai.io/">VISxAI</a>. Explainability is crucial for building trust in AI systems and ensuring that they make decisions based on valid reasoning. One of the areas that has seen the most investment in recent years is model grounding, the process of tying the model’s predictions to specific features in the input data. This is particularly important in applications such as image classification and question answering, where it is essential to understand which parts of an input (text, image) are driving the model’s predictions.</p> <pre><code class="language-plotly">{"data": [{"customdata": [["explainability"], ["explainability"], ["explainability"], ["explainability"], ["explainability"], ["explainability"], ["explainability"], ["explainability"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "explainability", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "explainability", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPuD8TYk4TYk6zPy5/O8fHSts/AjGEv/Me0D8LrqN3/DDgP76sEqjoLd0/CgP2acj/0j+61RmpmFvdPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["grounding"], ["grounding"], ["grounding"], ["grounding"], ["grounding"], ["grounding"], ["grounding"], ["grounding"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "grounding", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "grounding", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "uSDjgowL0j9WLrhVLrjlP0kPVM5u4ec/NqGesldY4z+1v65mtH7qP11Ii+URofE/lYMGxlBk9j9ZApv2kyX6Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["interpretability"], ["interpretability"], ["interpretability"], ["interpretability"], ["interpretability"], ["interpretability"], ["interpretability"], ["interpretability"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "interpretability", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "interpretability", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "uSDjgowL4j+Y+iGY+iHYP3Dn+Fhpw/I/KQXYtf6J8j+XwbYIZe3wPyM7FLZmnO8/t4JSzKn28D9C9PguHETzPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["traceability"], ["traceability"], ["traceability"], ["traceability"], ["traceability"], ["traceability"], ["traceability"], ["traceability"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "traceability", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "traceability", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC61RmpmFudPw=="}, "yaxis": "y", "type": "scatter"}], "layout": {"legend": {"title": {"text": "word"}, "tracegroupgap": 0}, "xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "year"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "occurrences (%)"}}}}
</code></pre> <p><strong>Visual tasks</strong> such as image denoising have received a lot of attention in recent years, with many papers published on the topic. This may be due to the increasing importance of image quality in computer vision applications, the development of new techniques to improve image quality, and the increased capacity of visual models to handle larger inputs. This category of tasks also includes deblurring, dehazing, demoireing, deraining, and others. Image processing and image generation tasks have also increased significantly.</p> <pre><code class="language-plotly">{"data": [{"customdata": [["colorization"], ["colorization"], ["colorization"], ["colorization"], ["colorization"], ["colorization"], ["colorization"], ["colorization"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "colorization", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "colorization", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "NOHPhD8T3j8dk/Uck/XMPy5/O8fHSts/AjGEv/Me0D+EcWIiEo23P/SPD4zsUMg/eQPQ5pu2tT+UJbBpP1nCPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["denoising"], ["denoising"], ["denoising"], ["denoising"], ["denoising"], ["denoising"], ["denoising"], ["denoising"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "denoising", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "denoising", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "5+ibo2+OBkAdk/Uck/UMQB4lzGKfbA1A6il7hTWhDkAHXUtAUZkLQPSPD4zsUAhAPIRNAY52CkB1RirmVucVQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["editing"], ["editing"], ["editing"], ["editing"], ["editing"], ["editing"], ["editing"], ["editing"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "editing", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "editing", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP6D/bxovaxovqP3Dn+Fhpw+I/Qj1lr7Am9D/HDwNNB9/zP4vlEaGp9vs/zYNzhLq/B0CNVMytzkgQQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["image enhancement"], ["image enhancement"], ["image enhancement"], ["image enhancement"], ["image enhancement"], ["image enhancement"], ["image enhancement"], ["image enhancement"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "image enhancement", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "image enhancement", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAACY+iGY+iHYPy5/O8fHSss/nYHTmB/L2T+1v65mtH7aP/SPD4zsUNg/CgP2acj/0j8Vc6szUjHfPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["image filling"], ["image filling"], ["image filling"], ["image filling"], ["image filling"], ["image filling"], ["image filling"], ["image filling"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "image filling", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "image filling", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "JUmSJEmS/D/8rMD7rMD7P4BBaL2RoQBAnYHTmB/LCUD4XU+RqdAGQMDBz028nghAQgNjKDJbBEC1nyyBTfsLQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["image generation"], ["image generation"], ["image generation"], ["image generation"], ["image generation"], ["image generation"], ["image generation"], ["image generation"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "image generation", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "image generation", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "2FBeQ3kN5T8dk/Uck/X8Py5/O8fHSvs/HGkRuaW7AUALrqN3/DAAQIrXkzLHAP8/lYMGxlBkBkC+CwfR47sOQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["image retrieval"], ["image retrieval"], ["image retrieval"], ["image retrieval"], ["image retrieval"], ["image retrieval"], ["image retrieval"], ["image retrieval"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "image retrieval", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "image retrieval", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "uSDjgowL8j9fX19fX1/vP2OfbNUVePQ/XHXyqGLD9T+XwbYIZe3wP8TkCmJyBeE/IAQXItnI6T+UJbBpP1niPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["image segmentation"], ["image segmentation"], ["image segmentation"], ["image segmentation"], ["image segmentation"], ["image segmentation"], ["image segmentation"], ["image segmentation"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "image segmentation", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "image segmentation", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "NOHPhD8T7j81SIM0SIP0P1x7phNsUvU/trlgktFn6z+cmIhE4wXpP/erC2mxPPI/CgP2acj/8j9VzK3OSMX4Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["image to image"], ["image to image"], ["image to image"], ["image to image"], ["image to image"], ["image to image"], ["image to image"], ["image to image"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "image to image", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "image to image", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP2D93FO12FO32P4RTS55mNABAT9krrAn19D8QhXWzekn4P4vlEaGp9us/CgP2acj/4j+n/WQJbNrnPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["localization"], ["localization"], ["localization"], ["localization"], ["localization"], ["localization"], ["localization"], ["localization"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "localization", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "localization", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "2FBeQ3kNFUAD77MC77MSQChbdQUeJQxAaRG5pbuRBkBxIQ48vywOQL2l03D3sg5ASsTocGjNCkC3OiMVc6sMQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["matching"], ["matching"], ["matching"], ["matching"], ["matching"], ["matching"], ["matching"], ["matching"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "matching", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "matching", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "Cn8m/JnwGUCcm5ubm5sTQHJwasnTjBJASYvILd2NFEDbIpS1w/8WQBCM7FDYmhNAV+PLz3ndFEA/WQKb9pMSQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["odometry"], ["odometry"], ["odometry"], ["odometry"], ["odometry"], ["odometry"], ["odometry"], ["odometry"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "odometry", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "odometry", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPyD+Y+iGY+iHYP2OfbNUVeNQ/0PHti4ME3T9UIxbeb5vUP/SPD4zsUMg/WASE4EIkyz+UJbBpP1nCPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["quality assessment"], ["quality assessment"], ["quality assessment"], ["quality assessment"], ["quality assessment"], ["quality assessment"], ["quality assessment"], ["quality assessment"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "quality assessment", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "quality assessment", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPyD8TYk4TYk7TPy5/O8fHSss/nYHTmB/LyT9UIxbeb5vUP44BDn5u4tU/mwIc7fRI0D84iB7fhYPgPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["reconstruction"], ["reconstruction"], ["reconstruction"], ["reconstruction"], ["reconstruction"], ["reconstruction"], ["reconstruction"], ["reconstruction"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "reconstruction", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "reconstruction", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "vYbyGsprEkDv2p/u2p8WQGOfbNUVeBRAgKIUYNf6F0DN5tSIhfcbQI3zjw+M7BhA3XI9f4LlIUCUJbBpP9keQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["removal"], ["removal"], ["removal"], ["removal"], ["removal"], ["removal"], ["removal"], ["removal"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "removal", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "removal", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "uSDjgowL8j9WLrhVLrj1P0kPVM5u4fc/T9krrAn19D/HDwNNB9/zPyM7FLZmnO8/xwReXRbb7T/mVmekYm7xPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["style transfer"], ["style transfer"], ["style transfer"], ["style transfer"], ["style transfer"], ["style transfer"], ["style transfer"], ["style transfer"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "style transfer", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "style transfer", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "uSDjgowL4j9fX19fX1/vPxTvIsAgtO4/HGkRuaW74T/HDwNNB9/zPylzDHDwc+M/xwReXRbb3T/mVmekYm7hPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["super resolution"], ["super resolution"], ["super resolution"], ["super resolution"], ["super resolution"], ["super resolution"], ["super resolution"], ["super resolution"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "super resolution", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "super resolution", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "2FBeQ3kNBUDrOSbrOSYLQEX9cO2ZTghAsGv9E6UAC0C0/HHkSr4QQFkeEZpqvwpAQgNjKDJbBECwaT9ZApsKQA=="}, "yaxis": "y", "type": "scatter"}], "layout": {"xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "year"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "occurrences (%)"}}, "legend": {"title": {"text": "task"}, "tracegroupgap": 0}}}
</code></pre> <p><strong>Language tasks</strong> have also seen a fluctuation in the number of papers published over the past few years, particularly those that focus on dialogue and conversation. By using a conversational interface, users can interact with AI systems in a more natural and intuitive way, leading to better user experiences and more effective communication. This has led to a surge in research on dialog systems, including chatbots, virtual assistants, and other conversational agents. The development of large-scale language models has also played a significant role in this trend, as these models have demonstrated impressive capabilities in generating human-like text and understanding context.</p> <pre><code class="language-plotly">{"data": [{"customdata": [["dialog"], ["dialog"], ["dialog"], ["dialog"], ["dialog"], ["dialog"], ["dialog"], ["dialog"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "dialog", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "dialog", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP2D/RleTQleTgPxTvIsAgtN4/nYHTmB/L2T/lDfuqVnDNPylzDHDwc8M/mwIc7fRIwD+dkYq51RnlPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["language translation"], ["language translation"], ["language translation"], ["language translation"], ["language translation"], ["language translation"], ["language translation"], ["language translation"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "language translation", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "language translation", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAATYk4TYk6zPwAAAAAAAAAAnYHTmB/LqT+EcWIiEo2nPylzDHDwc7M/eQPQ5pu2pT+61RmpmFudPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["question answering"], ["question answering"], ["question answering"], ["question answering"], ["question answering"], ["question answering"], ["question answering"], ["question answering"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "question answering", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "question answering", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "FbFUxFIR6z8TYk4TYk7zP3Dn+Fhpw+I/nYHTmB/L2T+EcWIiEo3XP/SPD4zsUNg/CgP2acj/4j9C9PguHETjPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["summarization"], ["summarization"], ["summarization"], ["summarization"], ["summarization"], ["summarization"], ["summarization"], ["summarization"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "summarization", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "summarization", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP6D+Y+iGY+iHYP2OfbNUVeMQ/nYHTmB/LuT+EcWIiEo23PylzDHDwc8M/eQPQ5pu2tT+UJbBpP1nCPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["text generation"], ["text generation"], ["text generation"], ["text generation"], ["text generation"], ["text generation"], ["text generation"], ["text generation"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "text generation", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "text generation", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACEcWIiEo2nPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="}, "yaxis": "y", "type": "scatter"}], "layout": {"legend": {"title": {"text": "task"}, "tracegroupgap": 0}, "xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "year"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "occurrences (%)"}}}}
</code></pre> <p><strong>Multimodal tasks</strong> are one of the current trends in artificial intelligence. These tasks involve the combination of different modalities, such as audio, text, and images, to improve the performance of models and to solve problems that require a deeper understanding of the intermodality of the world. The number of papers published on these tasks has increased significantly in recent years, with a particular focus on tasks such as image-text alignment, image synthesis, video synthesis, and visual question answering. This trend is likely to continue as researchers explore new ways to combine different modalities in novel ways and improve the performance of models.</p> <pre><code class="language-plotly">{"data": [{"customdata": [["alignment"], ["alignment"], ["alignment"], ["alignment"], ["alignment"], ["alignment"], ["alignment"], ["alignment"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "alignment", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "alignment", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "5+ibo2+OBkAD77MC77MCQGCNifRA5QRAiZepHZqVCEAo6V5T4gEQQHYobM04/xJAV+PLz3ndFECuzkjF3OoZQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["audio synthesis"], ["audio synthesis"], ["audio synthesis"], ["audio synthesis"], ["audio synthesis"], ["audio synthesis"], ["audio synthesis"], ["audio synthesis"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "audio synthesis", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "audio synthesis", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAClzDHDwc7M/eQPQ5pu2tT+61RmpmFudPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["captioning"], ["captioning"], ["captioning"], ["captioning"], ["captioning"], ["captioning"], ["captioning"], ["captioning"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "captioning", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "captioning", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "JUmSJEmS/D/yexnyexnyP3YLvxoT6fE/T9krrAn15D9UIxbeb5vkP76sEqjoLe0/mwIc7fRI8D/5LhxEj+/2Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["image synthesis"], ["image synthesis"], ["image synthesis"], ["image synthesis"], ["image synthesis"], ["image synthesis"], ["image synthesis"], ["image synthesis"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "image synthesis", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "image synthesis", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "2FBeQ3kN5T8dk/Uck/X8Py5/O8fHSvs/HGkRuaW7AUALrqN3/DAAQIrXkzLHAP8/lYMGxlBkBkC+CwfR47sOQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["referring expression comprehension"], ["referring expression comprehension"], ["referring expression comprehension"], ["referring expression comprehension"], ["referring expression comprehension"], ["referring expression comprehension"], ["referring expression comprehension"], ["referring expression comprehension"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "referring expression comprehension", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "referring expression comprehension", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPuD8TYk4TYk7DPy5/O8fHSrs/NqGesldYwz+EcWIiEo23PylzDHDwc6M/CgP2acj/0j+61RmpmFu9Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["video question answering"], ["video question answering"], ["video question answering"], ["video question answering"], ["video question answering"], ["video question answering"], ["video question answering"], ["video question answering"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "video question answering", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "video question answering", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAATYk4TYk6zPy5/O8fHSqs/NqGesldYwz+EcWIiEo3HP/SPD4zsUMg/mwIc7fRI4D9LYNN+sgTWPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["video synthesis"], ["video synthesis"], ["video synthesis"], ["video synthesis"], ["video synthesis"], ["video synthesis"], ["video synthesis"], ["video synthesis"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "video synthesis", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "video synthesis", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAATYk4TYk7TP0kPVM5u4dc/NqGesldY0z8j1cmZzanRP/SPD4zsUNg/xwReXRbb3T+P78JB9PjwPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["visual grounding"], ["visual grounding"], ["visual grounding"], ["visual grounding"], ["visual grounding"], ["visual grounding"], ["visual grounding"], ["visual grounding"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "visual grounding", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "visual grounding", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPuD8dk/Uck/XMPy5/O8fHSrs/nYHTmB/LuT8j1cmZzanRPylzDHDwc9M/CgP2acj/0j9eOIge34XbPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["visual question answering"], ["visual question answering"], ["visual question answering"], ["visual question answering"], ["visual question answering"], ["visual question answering"], ["visual question answering"], ["visual question answering"]], "hovertemplate": "task=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "visual question answering", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "visual question answering", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "yLgg44KM8z8+eSo+eSr+P1x7phNsUvU/D81KvEzt8D8LrqN3/DDwP76sEqjoLe0/CgP2acj/8j9QlsCm/WT3Pw=="}, "yaxis": "y", "type": "scatter"}], "layout": {"xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "year"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "occurrences (%)"}}, "legend": {"title": {"text": "task"}, "tracegroupgap": 0}}}
</code></pre> <p>Here we focus on analyzing the use of some keywords in the LLM papers. More specifically:</p> <ul> <li><strong>Chain-of-Thought</strong>, <strong>Tree-of-Thought</strong>, and any <strong>of-Thought</strong> variations - these are prompting techniques that help the model to break down complex tasks into smaller, more manageable steps, allowing it to reason through the problem more effectively;</li> <li><strong>Agent</strong> - refers to the use of LLMs as agents that can perform tasks autonomously, often in conjunction with other tools or systems;</li> <li><strong>Distillation</strong> - a technique used to compress large models into smaller, more efficient ones while retaining their performance;</li> <li><strong>Few-shot prompting</strong> - a prompting technique that provides the model with a few examples of the task at hand, allowing it to generalize and perform well on similar tasks;</li> <li><strong>Fine-tuning</strong> - the process of training a pre-trained model on a specific task or dataset to improve its performance;</li> <li><strong>Reinforcement Learning (RL)</strong> - a type of machine learning where an agent learns to make decisions by receiving feedback from its environment in the form of rewards or penalties;</li> <li><strong>Retrieval Augmented Generation (RAG)</strong> - a technique that combines retrieval-based methods with generative models to improve the performance of language models on specific tasks;</li> <li><strong>Self-Instruct</strong> - a technique that allows models to learn from their own outputs, improving their performance over time;</li> <li><strong>Tokenizer</strong> - a component of language models that converts text into a format that the model can understand, often by breaking it down into smaller units called tokens;</li> <li><strong>Tool</strong> - refers to the use of external tools or systems in conjunction with LLMs to perform tasks more effectively;</li> <li><strong>Zero-shot prompting</strong> - a prompting technique that allows the model to perform tasks without any prior examples or training on that specific task.</li> </ul> <p>Few-shot and zero-shot prompting have lost the interest of the academic community in favor of RAG, thought processes, and novel fine-tuning techniques. Interest in creating LLM agents that can tackle harder tasks and use tools is one of the hottest topics in the field.</p> <pre><code class="language-plotly">{"data": [{"customdata": [["* of thought"], ["* of thought"], ["* of thought"], ["* of thought"], ["* of thought"], ["* of thought"], ["* of thought"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "* of thought", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "* of thought", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+QH5QfmB+cH6Ac="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfDQhL2wVBEA="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["agent"], ["agent"], ["agent"], ["agent"], ["agent"], ["agent"], ["agent"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "agent", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "agent", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+QH5QfmB+cH6Ac="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbUZmK5zHEA="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["distillation"], ["distillation"], ["distillation"], ["distillation"], ["distillation"], ["distillation"], ["distillation"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "distillation", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "distillation", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+QH5QfmB+cH6Ac="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJQI7jOI7jOBZAus6xRiIgDkA="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["few shot"], ["few shot"], ["few shot"], ["few shot"], ["few shot"], ["few shot"], ["few shot"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "few shot", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "few shot", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+QH5QfmB+cH6Ac="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKuqqqqqqjBAMU653d/BJUA="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["finetuning"], ["finetuning"], ["finetuning"], ["finetuning"], ["finetuning"], ["finetuning"], ["finetuning"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "finetuning", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "finetuning", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+QH5QfmB+cH6Ac="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI7jOI7jOCZAus6xRiIgLkA="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["reinforcement learning"], ["reinforcement learning"], ["reinforcement learning"], ["reinforcement learning"], ["reinforcement learning"], ["reinforcement learning"], ["reinforcement learning"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "reinforcement learning", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "reinforcement learning", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+QH5QfmB+cH6Ac="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAASUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKuqqqqqqjBA3P0dXPaGQEA="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["retrieval augmented generation"], ["retrieval augmented generation"], ["retrieval augmented generation"], ["retrieval augmented generation"], ["retrieval augmented generation"], ["retrieval augmented generation"], ["retrieval augmented generation"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "retrieval augmented generation", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "retrieval augmented generation", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+QH5QfmB+cH6Ac="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAOUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJQKuqqqqqqkBAayQC4qMJQ0A="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["tokenizer"], ["tokenizer"], ["tokenizer"], ["tokenizer"], ["tokenizer"], ["tokenizer"], ["tokenizer"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "tokenizer", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "tokenizer", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+QH5QfmB+cH6Ac="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfDQhL2wV9D8="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["tool"], ["tool"], ["tool"], ["tool"], ["tool"], ["tool"], ["tool"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "tool", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "tool", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+QH5QfmB+cH6Ac="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAOUAAAAAAAAAAAAAAAAAAAElAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMU653d/BFUA="}, "yaxis": "y", "type": "scatter"}, {"customdata": [["zero shot"], ["zero shot"], ["zero shot"], ["zero shot"], ["zero shot"], ["zero shot"], ["zero shot"]], "hovertemplate": "word=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "zero shot", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "zero shot", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+QH5QfmB+cH6Ac="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJQBzHcRzHcUNAoifVVzI/M0A="}, "yaxis": "y", "type": "scatter"}], "layout": {"legend": {"title": {"text": "word"}, "tracegroupgap": 0}, "xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "year"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "occurrences (%)"}}}}
</code></pre> <h2 id="information-about-authors">Information about Authors</h2> <p>Now let’s look at the authors of the papers. This first graph shows the number of papers published by each author. As we can see, most authors have published only one paper at the conference. Out of 33,861 authors, only 1,308 have 10 or more accepted papers.</p> <pre><code class="language-plotly">{"data": [{"hovertemplate": "Number of papers=%{text}&lt;br&gt;Authors=%{y}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "", "marker": {"pattern": {"shape": ""}}, "name": "", "orientation": "v", "showlegend": false, "text": {"dtype": "f8", "bdata": "AAAAAADAYEAAAAAAAMBdQAAAAAAAAFlAAAAAAACAVUAAAAAAAMBUQAAAAAAAAFRAAAAAAADAU0AAAAAAAMBSQAAAAAAAwFFAAAAAAACAUUAAAAAAAEBRQAAAAAAAgFBAAAAAAABAUEAAAAAAAABQQAAAAAAAgE9AAAAAAAAAT0AAAAAAAIBOQAAAAAAAgE1AAAAAAAAATUAAAAAAAABMQAAAAAAAgEtAAAAAAAAAS0AAAAAAAIBKQAAAAAAAAEpAAAAAAACASUAAAAAAAABJQAAAAAAAgEhAAAAAAAAASEAAAAAAAIBHQAAAAAAAAEdAAAAAAAAARkAAAAAAAIBFQAAAAAAAAEVAAAAAAACAREAAAAAAAABEQAAAAAAAgENAAAAAAAAAQ0AAAAAAAIBCQAAAAAAAAEJAAAAAAACAQUAAAAAAAABBQAAAAAAAgEBAAAAAAAAAQEAAAAAAAAA/QAAAAAAAAD5AAAAAAAAAPUAAAAAAAAA8QAAAAAAAADtAAAAAAAAAOkAAAAAAAAA5QAAAAAAAADhAAAAAAAAAN0AAAAAAAAA2QAAAAAAAADVAAAAAAAAANEAAAAAAAAAzQAAAAAAAADJAAAAAAAAAMUAAAAAAAAAwQAAAAAAAAC5AAAAAAAAALEAAAAAAAAAqQAAAAAAAAChAAAAAAAAAJkAAAAAAAAAkQAAAAAAAACJAAAAAAAAAIEAAAAAAAAAcQAAAAAAAABhAAAAAAAAAFEAAAAAAAAAQQAAAAAAAAAhAAAAAAAAAAEAAAAAAAADwPw=="}, "textposition": "auto", "x": {"dtype": "i2", "bdata": "hgB3AGQAVgBTAFAATwBLAEcARgBFAEIAQQBAAD8APgA9ADsAOgA4ADcANgA1ADQAMwAyADEAMAAvAC4ALAArACoAKQAoACcAJgAlACQAIwAiACEAIAAfAB4AHQAcABsAGgAZABgAFwAWABUAFAATABIAEQAQAA8ADgANAAwACwAKAAkACAAHAAYABQAEAAMAAgABAA=="}, "xaxis": "x", "y": {"dtype": "i2", "bdata": "AQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAIAAQABAAEABQAEAAIAAQABAAMAAQACAAIABAABAAIABAAEAAQAAgAHAAgACwAGAAsABAAFAAYAFAALABIACwASABEAEgAVAB4AGAAWACQAIgAyACMALABAAFEAWABrAHsAlgCzAAIBKgGeAUMCSQOXBW8J3RU8UQ=="}, "yaxis": "y", "type": "bar"}], "layout": {"xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "Number of papers"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "Authors"}}, "legend": {"tracegroupgap": 0}, "barmode": "relative"}}
</code></pre> <p>Here are the top 10 authors with the most papers:</p> <table> <thead> <tr> <th>Author</th> <th>Papers</th> </tr> </thead> <tbody> <tr> <td>Luc Van Gool</td> <td>134</td> </tr> <tr> <td>Radu Timofte</td> <td>119</td> </tr> <tr> <td>Lei Zhang</td> <td>100</td> </tr> <tr> <td>Yi Yang</td> <td>86</td> </tr> <tr> <td>Yu Qiao</td> <td>83</td> </tr> <tr> <td>Dacheng Tao</td> <td>80</td> </tr> <tr> <td>Ming-Hsuan Yang</td> <td>79</td> </tr> <tr> <td>Qi Tian</td> <td>75</td> </tr> <tr> <td>Marc Pollefeys</td> <td>71</td> </tr> <tr> <td>Xiaogang Wang</td> <td>70</td> </tr> </tbody> </table> <p>Now let’s look at the number of authors per paper. Most of the papers have between 2 and 7 authors, but there are a few with a large number of authors, such as <a href="https://openaccess.thecvf.com/content/CVPR2023/html/Eisenmann_Why_Is_the_Winner_the_Best_CVPR_2023_paper.html">Why Is the Winner the Best?</a>, which has 125 authors, and <a href="https://openaccess.thecvf.com/content/CVPR2024W/NTIRE/html/Ren_The_Ninth_NTIRE_2024_Efficient_Super-Resolution_Challenge_Report_CVPRW_2024_paper.html">The Ninth NTIRE 2024 Efficient Super-Resolution Challenge Report</a>, with a staggering 134 authors. The former is a multi-center study of all 80 competitions held as part of IEEE ISBI 2021 and MICCAI 2021, while the latter is a report summarizing the results of the NTIRE 2024 challenge, a competition held at the CVPR conference.</p> <pre><code class="language-plotly">{"data": [{"hovertemplate": "Number of authors=%{x}&lt;br&gt;Number of papers=%{text}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "", "marker": {"pattern": {"shape": ""}}, "name": "", "orientation": "v", "showlegend": false, "text": {"dtype": "f8", "bdata": "AAAAAAAgZ0AAAAAAAByWQAAAAAAAoqZAAAAAAAAArEAAAAAAAE6pQAAAAAAA2KJAAAAAAADklkAAAAAAALiIQAAAAAAA0HhAAAAAAADAaUAAAAAAAIBcQAAAAAAAAFBAAAAAAAAAOUAAAAAAAAA3QAAAAAAAACRAAAAAAAAAJkAAAAAAAAAQQAAAAAAAAABAAAAAAAAA8D8AAAAAAAAQQAAAAAAAAABAAAAAAAAAAEAAAAAAAAAQQAAAAAAAAAhAAAAAAAAA8D8AAAAAAAAIQAAAAAAAAPA/AAAAAAAA8D8AAAAAAADwPwAAAAAAAPA/AAAAAAAAAEAAAAAAAAAAQAAAAAAAAPA/AAAAAAAA8D8AAAAAAAAAQAAAAAAAAPA/AAAAAAAA8D8AAAAAAADwPwAAAAAAAPA/AAAAAAAA8D8AAAAAAADwPwAAAAAAAPA/AAAAAAAACEAAAAAAAADwPwAAAAAAAPA/AAAAAAAACEAAAAAAAADwPwAAAAAAAPA/AAAAAAAA8D8AAAAAAADwPwAAAAAAAPA/AAAAAAAA8D8AAAAAAADwPwAAAAAAAPA/AAAAAAAA8D8AAAAAAADwPwAAAAAAAPA/AAAAAAAA8D8="}, "textposition": "auto", "x": {"dtype": "i2", "bdata": "AQACAAMABAAFAAYABwAIAAkACgALAAwADQAOAA8AEAARABIAEwAUABUAFgAXABgAGwAcAB8AIQAiACMAJAAlACcAKQAqACsALQAwADEANQA3ADgAOgBCAEMARABOAE8AVQBYAF0AZABlAGwAcQBzAH0AhgA="}, "xaxis": "x", "y": {"dtype": "i2", "bdata": "uQCHBVELAA6nDGwJuQUXA40BzgByAEAAGQAXAAoACwAEAAIAAQAEAAIAAgAEAAMAAQADAAEAAQABAAEAAgACAAEAAQACAAEAAQABAAEAAQABAAEAAwABAAEAAwABAAEAAQABAAEAAQABAAEAAQABAAEAAQA="}, "yaxis": "y", "type": "bar"}], "layout": {"xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "Number of authors"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "Number of papers"}}, "legend": {"tracegroupgap": 0}, "barmode": "relative"}}
</code></pre> <p>Since most papers have multiple authors, it is quite common to see some authors constantly collaborating with each other. The most common pair of authors is Jiwen Lu and Jie Zhou, who have collaborated on 57 papers together. The second most common pair is Luc Van Gool and Radu Timofte with 43 papers together, followed by Tao Xiang and Yi-Zhe Song with 38 papers. The top 10 most frequent pairs of authors are:</p> <table> <thead> <tr> <th>Author 1</th> <th>Author 2</th> <th>Papers</th> </tr> </thead> <tbody> <tr> <td>Jiwen Lu</td> <td>Jie Zhou</td> <td>57</td> </tr> <tr> <td>Luc Van Gool</td> <td>Radu Timofte</td> <td>43</td> </tr> <tr> <td>Tao Xiang</td> <td>Yi-Zhe Song</td> <td>38</td> </tr> <tr> <td>Fahad Shahbaz Khan</td> <td>Salman Khan</td> <td>33</td> </tr> <tr> <td>Ting Yao</td> <td>Tao Mei</td> <td>32</td> </tr> <tr> <td>Xiaogang Wang</td> <td>Hongsheng Li</td> <td>28</td> </tr> <tr> <td>Shiguang Shan</td> <td>Xilin Chen</td> <td>27</td> </tr> <tr> <td>Richa Singh</td> <td>Mayank Vatsa</td> <td>26</td> </tr> <tr> <td>Dong Chen</td> <td>Fang Wen</td> <td>24</td> </tr> <tr> <td>Yi-Zhe Song</td> <td>Ayan Kumar Bhunia</td> <td>24</td> </tr> </tbody> </table> <p>Although it is quite rare for a paper to have a single author, 185 papers fall into this category. A few worthy mentions are research that introduced novel loss functions (<a href="https://openaccess.thecvf.com/content_CVPR_2019/html/Barron_A_General_and_Adaptive_Robust_Loss_Function_CVPR_2019_paper.html">Jonathan T. Barron</a>, <a href="https://openaccess.thecvf.com/content/CVPR2023/html/Kobayashi_Two-Way_Multi-Label_Loss_CVPR_2023_paper.html">Takumi Kobayashi</a>) and improved transformer architectures and post-training techniques (<a href="https://openaccess.thecvf.com/content/CVPR2024/html/Kobayashi_Mean-Shift_Feature_Transformer_CVPR_2024_paper.html">Takumi Kobayashi</a>, <a href="https://openaccess.thecvf.com/content/CVPR2024/html/Ma_Improved_Self-Training_for_Test-Time_Adaptation_CVPR_2024_paper.html">Jing Ma</a>). In this table we can see the authors with the most papers where they are the only author:</p> <table> <thead> <tr> <th>Author</th> <th>Papers</th> </tr> </thead> <tbody> <tr> <td>Takumi Kobayashi</td> <td>4</td> </tr> <tr> <td>Anant Khandelwal, Takuhiro Kaneko</td> <td>3</td> </tr> <tr> <td>Andrey V. Savchenko, Chong Yu, Dimitrios Kollias, Edgar A. Bernal, Jamie Hayes, Magnus Oskarsson, Ming Li, Oleksii Sidorov, Ren Yang, Rowel Atienza, Sanghwa Hong, Satoshi Ikehata, Shunta Maeda, Stamatios Lefkimmiatis, Ying Zhao</td> <td>2</td> </tr> </tbody> </table> <h2 id="identifying-topics">Identifying Topics</h2> <p>For this section, we used <a href="https://arxiv.org/abs/2008.09470">Top2Vec</a>, an automatic topic modeling algorithm, to identify groups of papers that are similar to each other based on their titles and abstracts. The solution found 172 topics, which is a bit too many for us to analyze individually. Instead, we will focus on the hottest and coldest topics, which are those with the most and least papers in the last year, respectively.</p> <p>One problem with the algorithm is that it identifies topics based on the words used in the papers, but it doesn’t provide a clear explanation of what those topics are about. This is a common problem with topic modeling algorithms, as they often produce results that are difficult to interpret. However, we can use LLMs to help us understand the meaning of these topics. We will use the most representative words of each topic (the words that appear most often in the papers of that topic) to generate a title and a paragraph summarizing it.</p> <h3 id="-10-topics">🔥 10 topics</h3> <pre><code class="language-plotly">{"data": [{"customdata": {"dtype": "i1", "bdata": "AQEBAQEBAQE=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "1", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "1", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAATYk4TYk6zPy5/O8fHSrs/nYHTmB/LqT8AAAAAAAAAAClzDHDwc6M/WASE4EIk2z+NVMytzkgQQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "AgICAgICAgI=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "2", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "2", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP2D9WLrhVLrjlPy5/O8fHSus/T9krrAn19D/gNilv2Ff1P1keEZpqv/o/IAQXItnICUBXZ6RibnUZQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "AwMDAwMDAwM=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "3", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "3", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "yLgg44KMA0DhCH/hCH8BQHodovvnewFAHGkRuaW7AUD4XU+RqdD2PyhljgEOfvY/XoOZB+cI9T/+ZAls2k8IQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "BAQEBAQEBAQ=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "4", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "4", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "AAAAAAAAAAATYk4TYk6zPy5/O8fHSrs/nYHTmB/LqT8AAAAAAAAAAClzDHDwc7M/CgP2acj/0j+rM1Ixtzr5Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "BQUFBQUFBQU=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "5", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "5", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "qYilIpaKAEBWLrhVLrgFQFZX4FHCLAZAL1M7NCvxAkCcmIhE4wX5P43zjw+M7Pg/mwIc7fRI4D8MB9Hju3D8Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "BgYGBgYGBgY=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "6", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "6", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "NOHPhD8T3j9WLrhVLrjlP0kPVM5u4ec/0PHti4ME3T87/O+7niLjP1keEZpqv9o/eQPQ5pu2tT9VzK3OSMXoPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "BwcHBwcHBwc=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "7", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "7", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPuD8AAAAAAAAAAAAAAAAAAAAAnYHTmB/LuT+EcWIiEo2nPylzDHDwc8M/0wKJq16k4T+ZW52RirnzPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "CAgICAgICAg=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "8", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "8", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "uSDjgowL4j9WLrhVLrjlPy5/O8fHSqs/NqGesldYwz+EcWIiEo3HPyM7FLZmnN8/AAAAAAAAAADwwkH0+C7kPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "CQkJCQkJCQk=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "9", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "9", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "NOHPhD8T/j9fX19fX1/vP3Dn+Fhpw+I/nYHTmB/L6T8j1cmZzanhP1keEZpqv9o/AAAAAAAAAACUJbBpP1niPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "CgoKCgoKCgo=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "10", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "10", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "uSDjgowL4j/RleTQleTgP2nDMpe/nfM/0PHti4ME3T+1v65mtH7qP/erC2mxPOI/0wKJq16k4T/mVmekYm7xPw=="}, "yaxis": "y", "type": "scatter"}], "layout": {"legend": {"title": {"text": "topic"}, "tracegroupgap": 0}, "xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "year"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "occurrences (%)"}}}}
</code></pre> <p>The topics below are listed in the order in which they had the most published articles last year.</p> <details> <summary><b>Topic 1 - Instruction-Tuned Multimodal LLMs for Vision-Language Understanding (157 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_23.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 1" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Recent advancements in large language models (LLMs) and multimodal large language models (MLLMs) have led to remarkable capabilities in integrating visual and textual information for tasks like question answering, dialogue, and reasoning. By leveraging instruction tuning and visual prompt techniques, these models — such as vision-language models (VLMs) like CLIP — have significantly improved in-context comprehension and instruction following across modalities. Despite these achievements, challenges like hallucinations and limited applicability in complex, real-world settings still remain. Research continues to focus on enhancing multimodal instruction learning to facilitate deeper, more reliable understanding between vision and language inputs. <br/> <br/> Top authors: <ol> <li>Yu Qiao (7 papers)</li> <li>Ying Shan (5 papers)</li> <li>Yixiao Ge (5 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2024W/MMFM/html/Wang_LLM-Seg_Bridging_Image_Segmentation_and_Large_Language_Model_Reasoning_CVPRW_2024_paper.html">LLM-Seg: Bridging Image Segmentation and Large Language Model Reasoning (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Guan_HallusionBench_An_Advanced_Diagnostic_Suite_for_Entangled_Language_Hallucination_and_CVPR_2024_paper.html">HallusionBench: An Advanced Diagnostic Suite for Entangled Language Hallucination and Visual Illusion in Large Vision-Language Models (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024W/CVsports/html/Nonaka_Rugby_Scene_Classification_Enhanced_by_Vision_Language_Model_CVPRW_2024_paper.html">Rugby Scene Classification Enhanced by Vision Language Model (2024)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 2 - Controllable Text-Guided Image Editing with Diffusion and GAN Inversion (426 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_3.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 2" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Advances in text-to-image diffusion models and GAN-based techniques have unlocked powerful, controllable image editing capabilities driven by natural language prompts. Methods like StyleGAN inversion, DDIM inversion, and textual inversion allow users to manipulate generated images or real inputs with high fidelity while preserving key features like identity. Text-guided editing leverages the latent space of pretrained diffusion and GAN models, enabling creative, precise, and personalized edits through simple prompts. Despite remarkable progress, achieving fine-grained control over complex edits and extending these capabilities to video editing remain active research challenges. <br/> <br/> Top authors: <ol> <li>Chen Change Loy (9 papers)</li> <li>Xintao Wang (8 papers)</li> <li>Ying Shan (8 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2024W/GCV/html/Bodur_iEdit_Localised_Text-guided_Image_Editing_with_Weak_Supervision_CVPRW_2024_paper.html">iEdit: Localised Text-guided Image Editing with Weak Supervision (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Guo_MoMask_Generative_Masked_Modeling_of_3D_Human_Motions_CVPR_2024_paper.html">MoMask: Generative Masked Modeling of 3D Human Motions (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Nam_Contrastive_Denoising_Score_for_Text-guided_Latent_Diffusion_Image_Editing_CVPR_2024_paper.html">Contrastive Denoising Score for Text-guided Latent Diffusion Image Editing (2024)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 3 - AI-Driven Medical Imaging and Diagnosis in Clinical Practice (345 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_5.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 3" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> The integration of computational methods into medical imaging and pathology has become increasingly important for improving diagnostic accuracy and early disease detection. Techniques like computer-aided diagnosis support clinicians in analyzing tissues, tumors, and organs across modalities such as histopathology, MRI, CT, and digital microscopy. Applications span cancer diagnosis (e.g., breast, brain, skin lesions), neurological diseases like Alzheimer's and Parkinson's, and blood analysis. By enhancing image analysis and tissue classification, these AI-driven tools aid in treatment planning and disease progression monitoring, making them vital in modern clinical practice and biomedical research. <br/> <br/> Top authors: <ol> <li>Le Lu (9 papers)</li> <li>Faisal Mahmood (5 papers)</li> <li>Ke Yan (5 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2023/html/Xiang_SQUID_Deep_Feature_In-Painting_for_Unsupervised_Anomaly_Detection_CVPR_2023_paper.html">SQUID: Deep Feature In-Painting for Unsupervised Anomaly Detection (2023)</a></li> <li><a href="https://openaccess.thecvf.com/content_cvpr_2017_workshops/w3/html/Mery_A_Logarithmic_X-Ray_CVPR_2017_paper.html">A Logarithmic X-Ray Imaging Model for Baggage Inspection: Simulation and Object Detection (2017)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2022/html/Haghighi_DiRA_Discriminative_Restorative_and_Adversarial_Learning_for_Self-Supervised_Medical_Image_CVPR_2022_paper.html">DiRA: Discriminative, Restorative, and Adversarial Learning for Self-Supervised Medical Image Analysis (2022)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 4 - Challenges and Advances in 3D-Aware Text-to-Image and Text-to-Video Generation (68 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_95.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 4" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Text-to-image and text-to-video generation using diffusion models has made remarkable progress, enabling the synthesis of high-fidelity, photorealistic assets from simple prompts. However, existing methods still struggle with accurately handling 3D geometry, novel views, and maintaining global and multi-view consistency. Techniques like diffusion priors, 3D Gaussians, and NeRF-based approaches aim to improve subject-driven generation and diverse, globally consistent outputs. Despite advances in pretrained diffusion models and anisotropic diffusion strategies, achieving high-fidelity, geometry-aware synthesis remains a central challenge in the evolution of text-to-3D and motion generation. <br/> <br/> Top authors: <ol> <li>Hsin-Ying Lee (4 papers)</li> <li>Sergey Tulyakov (4 papers)</li> <li>Ying Shan (4 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Kim_Enhancing_3D_Fidelity_of_Text-to-3D_using_Cross-View_Correspondences_CVPR_2024_paper.html">Enhancing 3D Fidelity of Text-to-3D using Cross-View Correspondences (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Liu_DIRECT-3D_Learning_Direct_Text-to-3D_Generation_on_Massive_Noisy_3D_Data_CVPR_2024_paper.html">DIRECT-3D: Learning Direct Text-to-3D Generation on Massive Noisy 3D Data (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Yi_Diffusion_Time-step_Curriculum_for_One_Image_to_3D_Generation_CVPR_2024_paper.html">Diffusion Time-step Curriculum for One Image to 3D Generation (2024)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 5 - Remote Sensing and Aerial Imagery for Environmental and Agricultural Monitoring (306 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_10.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 5" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> The rapid development of satellite and unmanned aerial vehicle (UAV) technologies has fueled increased interest in using high-resolution imagery for environmental, agricultural, and urban management. Remote sensing enables the monitoring of plant species, crop types, water resources, land cover changes, and urban infrastructure such as roads and buildings, particularly aiding developing countries. Applications range from crop management and plant phenotyping to traffic management and tracking environmental factors and changes. Publicly accessible satellite and aerial datasets are becoming vital tools for tackling global challenges in resource management, environmental protection, and urban planning. <br/> <br/> Top authors: <ol> <li>Sara Beery (5 papers)</li> <li>David Lobell (4 papers)</li> <li>Edward J. Delp (4 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content_cvpr_2018/html/Mahjourian_Unsupervised_Learning_of_CVPR_2018_paper.html">Unsupervised Learning of Depth and Ego-Motion From Monocular Video Using 3D Geometric Constraints (2018)</a></li> <li><a href="https://openaccess.thecvf.com/content_cvpr_2018_workshops/w4/html/Hamaguchi_Building_Detection_From_CVPR_2018_paper.html">Building Detection From Satellite Imagery Using Ensemble of Size-Specific Detectors (2018)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2021W/AI4Space/html/Oestreich_On-Orbit_Inspection_of_an_Unknown_Tumbling_Target_Using_NASAs_Astrobee_CVPRW_2021_paper.html">On-Orbit Inspection of an Unknown, Tumbling Target Using NASA's Astrobee Robotic Free-Flyers (2021)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 6 - Competitions and Challenges in Computer Vision: The Role of NTIRE and Beyond (90 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_66.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 6" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Large-scale competitions like the NTIRE Challenge, MegaFace Challenge, and ABAW Competition have become central to advancing computer vision research. Hosted at major conferences like CVPR, these challenges attract hundreds of registered participants and teams, competing across various tracks such as perceptual quality, AI-generated content, and traffic analysis. Through rigorous submissions and evaluations on standardized test sets, these challenges foster innovation, benchmark progress, and tackle formidable problems in the field. The NTIRE Workshop, in particular, has established itself as a premier platform for recognizing outstanding achievements and setting new frontiers in computer vision competitions. <br/> <br/> Top authors: <ol> <li>Radu Timofte (44 papers)</li> <li>Marcos V. Conde (8 papers)</li> <li>Radu Timofte (7 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2022W/NTIRE/html/Perez-Pellitero_NTIRE_2022_Challenge_on_High_Dynamic_Range_Imaging_Methods_and_CVPRW_2022_paper.html">NTIRE 2022 Challenge on High Dynamic Range Imaging: Methods and Results (2022)</a></li> <li><a href="https://openaccess.thecvf.com/content_cvpr_2017_workshops/w12/html/Bae_Beyond_Deep_Residual_CVPR_2017_paper.html">Beyond Deep Residual Learning for Image Restoration: Persistent Homology-Guided Manifold Simplification (2017)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024W/NTIRE/html/Vasluianu_NTIRE_2024_Image_Shadow_Removal_Challenge_Report_CVPRW_2024_paper.html">NTIRE 2024 Image Shadow Removal Challenge Report (2024)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 7 - Enhancing Diffusion Models: Faster Inference and Higher Image Quality (64 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_103.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 7" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Diffusion models have emerged as powerful tools for generating high-quality images, particularly in text-to-image tasks, but they often suffer from slow inference speeds and inherent limitations tied to their timestep-based denoising process. Recent advances focus on accelerating inference and improving FID scores through innovations like post-training quality enhancement, tailored token mixing (e.g., super tokens, OCR tokens), and anisotropic diffusion strategies. These methods can be flexibly applied with negligible computational overhead, substantially improving image quality without retraining. By addressing inherent inefficiencies and showcasing superior performance, these techniques represent a major step forward in diffusion-based image generation. <br/> <br/> Top authors: <ol> <li>Deli Zhao (3 papers)</li> <li>Yujun Shen (3 papers)</li> <li>Chengyue Gong (2 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2023/html/Liu_FlowGrad_Controlling_the_Output_of_Generative_ODEs_With_Gradients_CVPR_2023_paper.html">FlowGrad: Controlling the Output of Generative ODEs With Gradients (2023)</a></li> <li><a href="https://openaccess.thecvf.com/content_CVPRW_2020/html/w1/B.S._Plug-and-Pipeline_Efficient_Regularization_for_Single-Step_Adversarial_Training_CVPRW_2020_paper.html">Plug-and-Pipeline: Efficient Regularization for Single-Step Adversarial Training (2020)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2023/html/Karpikova_FIANCEE_Faster_Inference_of_Adversarial_Networks_via_Conditional_Early_Exits_CVPR_2023_paper.html">FIANCEE: Faster Inference of Adversarial Networks via Conditional Early Exits (2023)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 8 - Intelligent Traffic Monitoring and Driver Behavior Analysis for Road Safety (58 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_107.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 8" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Advances in intelligent transportation systems are increasingly focused on improving road safety through the analysis of driver behavior, traffic scenarios, and vehicle-pedestrian interactions. By leveraging traffic monitoring, naturalistic driving datasets, and leaderboard-driven challenges, researchers aim to develop better driver assistance systems and accident prevention technologies. Areas like distracted driver detection, traffic surveillance, and automated driving benefit from smart monitoring systems that enhance safe driving practices and reduce traffic accidents. As public leaderboards rank the best published methods, innovations in vehicle tracking, intelligent traffic analysis, and safe transportation continue to accelerate progress toward safer roads. <br/> <br/> Top authors: <ol> <li>Armstrong Aboah (3 papers)</li> <li>Fei Su (3 papers)</li> <li>Zhe Cui (3 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2024W/AICity/html/Chen_An_Effective_Method_for_Detecting_Violation_of_Helmet_Rule_for_CVPRW_2024_paper.html">An Effective Method for Detecting Violation of Helmet Rule for Motorcyclists (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2022W/AICity/html/Liang_Stargazer_A_Transformer-Based_Driver_Action_Detection_System_for_Intelligent_Transportation_CVPRW_2022_paper.html">Stargazer: A Transformer-Based Driver Action Detection System for Intelligent Transportation (2022)</a></li> <li><a href="https://openaccess.thecvf.com/content_cvpr_2017_workshops/w4/html/Reddy_Real-Time_Driver_Drowsiness_CVPR_2017_paper.html">Real-Time Driver Drowsiness Detection for Embedded System Using Model Compression of Deep Neural Networks (2017)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 9 - Soccer and Sports Video Analytics: Player Tracking and Game Understanding (103 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_54.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 9" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Advances in sports video analytics, particularly for soccer, focus on tracking players, analyzing game states, and generating highlights from broadcast footage and sport-specific datasets. Systems capable of detecting player positions, ball movements, and team dynamics have become fundamental tools for both game analysis and automated content production. Publicly released datasets like UCF and HMDB, along with open-source code, drive innovation in this field, enabling teams around the world to develop systems capable of capturing, processing, and understanding complex sport scenarios. These developments are reshaping sports analytics, enhancing performance evaluation, and enriching fan experiences. <br/> <br/> Top authors: <ol> <li>Anthony Cioppa (11 papers)</li> <li>Marc Van Droogenbroeck (10 papers)</li> <li>Bernard Ghanem (8 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content_CVPRW_2020/html/w45/Ramaswamy_Spatio-Temporal_Action_Detection_and_Localization_Using_a_Hierarchical_LSTM_CVPRW_2020_paper.html">Spatio-Temporal Action Detection and Localization Using a Hierarchical LSTM (2020)</a></li> <li><a href="https://openaccess.thecvf.com/content_cvpr_2018_workshops/w34/html/Giancola_SoccerNet_A_Scalable_CVPR_2018_paper.html">SoccerNet: A Scalable Dataset for Action Spotting in Soccer Videos (2018)</a></li> <li><a href="https://openaccess.thecvf.com/content_cvpr_2017/html/Hu_Deep_360_Pilot_CVPR_2017_paper.html">Deep 360 Pilot: Learning a Deep Agent for Piloting Through 360deg Sports Videos (2017)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 10 - Event-Based Vision: High-Speed, Low-Latency Sensing with Neuromorphic Cameras (129 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_34.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 10" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Event-based vision, powered by bio-inspired neuromorphic cameras, represents a major shift from traditional frame-based imaging. Unlike conventional sensors, event cameras capture asynchronous changes in brightness with low latency, low power consumption, and exceptional dynamic range, making them ideal for high-speed motion scenarios and environments prone to motion blur. This technology, including event-based vision for video frame interpolation (VFI) and eye tracking, has progressed rapidly, offering advantages in bandwidth efficiency and noise reduction. Applications span robotics, autonomous driving, and high-speed tracking, where conventional frame-based approaches often fall short. <br/> <br/> Top authors: <ol> <li>Davide Scaramuzza (11 papers)</li> <li>Mathias Gehrig (6 papers)</li> <li>Boxin Shi (5 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2022/html/Deng_A_Voxel_Graph_CNN_for_Object_Classification_With_Event_Cameras_CVPR_2022_paper.html">A Voxel Graph CNN for Object Classification With Event Cameras (2022)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Sundar_Generalized_Event_Cameras_CVPR_2024_paper.html">Generalized Event Cameras (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Yu_EventPS_Real-Time_Photometric_Stereo_Using_an_Event_Camera_CVPR_2024_paper.html">EventPS: Real-Time Photometric Stereo Using an Event Camera (2024)</a></li> </ul> <hr/> </details> <h3 id="-10-topics-1">🧊 10 topics</h3> <pre><code class="language-plotly">{"data": [{"customdata": {"dtype": "i1", "bdata": "AQEBAQEBAQE=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "1", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "1", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPuD8TYk4TYk7DPy5/O8fHSss/aRG5pbuR1j/N5tSIhffrP1keEZpqv+o/jwTxnqx//D84iB7fhYPgPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "AgICAgICAgI=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "2", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "2", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "sVTEUhFLAUDyexnyexkCQC5/O8fHSvs/T9krrAn19D+1v65mtH76P8HIDoWtGQdAviIgBBciEUBVzK3OSMUIQA=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "AwMDAwMDAwM=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "3", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "3", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPuD+Y+iGY+iHYPy5/O8fHSts/0PHti4ME7T+cmIhE4wX5P76sEqjoLf0/IAQXItnI+T9VzK3OSMXoPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "BAQEBAQEBAQ=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "4", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "4", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YP6D8+eSo+eSr+P23VFXiUMANAAjGEv/MeAEBiIhKNF2QJQCM7FLZmnP8/44SUPMuI/j89vgsH0ePxPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "BQUFBQUFBQU=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "5", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "5", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPyD+Y+iGY+iHYP2OfbNUVeOQ/AjGEv/Me8D8LrqN3/DDwPyhljgEOfvY/JoMsSX2tA0C1nyyBTfv7Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "BgYGBgYGBgY=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "6", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "6", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "77S60+pOB0DhCH/hCH8BQELrjQzFu/g/HGkRuaW78T8j1cmZzanxP/SPD4zsUPg/BITgQiQb+T+61RmpmFvtPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "BwcHBwcHBwc=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "7", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "7", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "qYilIpaK8D8TYk4TYk7zP2OfbNUVeOQ/0PHti4ME7T/N5tSIhffrP1w6DXcvq+Q/PIRNAY52+j/hIHp8Fw7wPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "CAgICAgICAg=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "8", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "8", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "uSDjgowL4j/RleTQleTgP3Dn+Fhpw+I/aRG5pbuR5j+1v65mtH7qP/eySqCitwBAmwIc7fRIAED5LhxEj+/2Pw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "CQkJCQkJCQk=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "9", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "9", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "9oDZA2YPyD8TYk4TYk6zPy5/O8fHSrs/NqGesldY0z+1v65mtH7aP76sEqjoLd0/mwIc7fRI8D9eOIge34XbPw=="}, "yaxis": "y", "type": "scatter"}, {"customdata": {"dtype": "i1", "bdata": "CgoKCgoKCgo=", "shape": "8, 1"}, "hovertemplate": "topic=%{customdata[0]}&lt;br&gt;year=%{x}&lt;br&gt;occurrences (%)=%{y:.3f}&lt;extra&gt;&lt;/extra&gt;", "legendgroup": "10", "line": {"dash": "solid"}, "marker": {"symbol": "circle"}, "mode": "lines+markers", "name": "10", "orientation": "v", "showlegend": true, "x": {"dtype": "i2", "bdata": "4QfiB+MH5AflB+YH5wfoBw=="}, "xaxis": "x", "y": {"dtype": "f8", "bdata": "2FBeQ3kNFUAdk/Uck/UMQGnDMpe/nQNAdq1/ohRgB0CKSDRekKX/P7+6kBbLI/o/lYMGxlBk9j+waT9ZApvqPw=="}, "yaxis": "y", "type": "scatter"}], "layout": {"xaxis": {"anchor": "y", "domain": [0.0, 1.0], "title": {"text": "year"}}, "yaxis": {"anchor": "x", "domain": [0.0, 1.0], "title": {"text": "occurrences (%)"}}, "legend": {"title": {"text": "topic"}, "tracegroupgap": 0}}}
</code></pre> <p>The topics below are listed in the order in which they had the largest decrease in papers over the last year.</p> <details> <summary><b>Topic 1 - Self-Supervised Pretraining: Masked Models and Their Impact on Downstream Vision Tasks (115 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_44.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 1" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Self-supervised pretraining has revolutionized machine learning by enabling models to learn from unlabeled data, significantly improving performance on a wide range of downstream vision tasks. Techniques like masked autoencoding and contrastive pretraining have become central to this approach, where a model is trained to predict missing parts of the data, learning rich representations without the need for labeled examples. These methods, including masked token strategies and large-scale pretraining on unlabeled video or image datasets, have shown to outperform traditional supervised pretraining, achieving great success across various applications. The benefits of self-supervised learning, especially in terms of scalability and performance, are now being extensively explored in vision-language pretraining (VLP) and other vision tasks, often surpassing existing supervised methods. <br/> <br/> Top authors: <ol> <li>Yu Qiao (9 papers)</li> <li>Ishan Misra (4 papers)</li> <li>Ross Girshick (4 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Liu_Solving_Masked_Jigsaw_Puzzles_with_Diffusion_Vision_Transformers_CVPR_2024_paper.html">Solving Masked Jigsaw Puzzles with Diffusion Vision Transformers (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content_cvpr_2017/html/Pathak_Learning_Features_by_CVPR_2017_paper.html">Learning Features by Watching Objects Move (2017)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024W/CV4MS/html/Kazimi_Self-Supervised_Learning_with_Generative_Adversarial_Networks_for_Electron_Microscopy_CVPRW_2024_paper.html">Self-Supervised Learning with Generative Adversarial Networks for Electron Microscopy (2024)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 2 - Vision-Language Models: Aligning Text and Image for Cross-Modal Understanding (432 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_2.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 2" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Vision-language models, such as CLIP, leverage large datasets of paired image-text data to learn the alignment between visual content and language. These models enable tasks like image captioning, where a description is generated for an image, and text-based image retrieval, where a sentence or phrase is used to find relevant visual content. Through pretraining on vast collections of images and their corresponding captions, these models achieve zero-shot capabilities, meaning they can generalize to tasks they were not explicitly trained on. Grounding text in visual concepts, such as matching sentences to images or videos, has become a central challenge in creating more sophisticated systems for understanding and generating visual and textual information across diverse domains, including untrimmed videos and spoken language. <br/> <br/> Top authors: <ol> <li>Lijuan Wang (9 papers)</li> <li>Mike Zheng Shou (7 papers)</li> <li>Ying Shan (7 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content_CVPR_2020/html/Chen_Image_Search_With_Text_Feedback_by_Visiolinguistic_Attention_Learning_CVPR_2020_paper.html">Image Search With Text Feedback by Visiolinguistic Attention Learning (2020)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2023/html/Gao_ULIP_Learning_a_Unified_Representation_of_Language_Images_and_Point_CVPR_2023_paper.html">ULIP: Learning a Unified Representation of Language, Images, and Point Clouds for 3D Understanding (2023)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Vasu_MobileCLIP_Fast_Image-Text_Models_through_Multi-Modal_Reinforced_Training_CVPR_2024_paper.html">MobileCLIP: Fast Image-Text Models through Multi-Modal Reinforced Training (2024)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 3 - Semi-Supervised Learning: Leveraging Unlabeled Data for Improved Model Performance (179 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_19.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 3" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Semi-supervised learning (SSL) is a powerful technique that utilizes both labeled and unlabeled data to train models, especially when labeled data is scarce. In SSL, pseudo-labeling is commonly employed, where unlabeled examples are assigned pseudo-labels based on model predictions, and these pseudo-labeled data are incorporated into the training process. This approach allows models to learn from a large amount of unlabeled data, improving generalization without requiring extensive labeled datasets. Methods like pseudo label refinement and self-training help ensure the quality and reliability of the pseudo-labels, making SSL effective for tasks like medical image analysis, where labeled data is limited. By combining labeled data with confident pseudo-labels from unlabeled examples, semi-supervised learning can outperform traditional fully supervised methods, particularly in challenging settings with partially labeled data. <br/> <br/> Top authors: <ol> <li>Jingdong Wang (4 papers)</li> <li>Lei Qi (4 papers)</li> <li>Yinghuan Shi (4 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Zhang_Decoupled_Pseudo-labeling_for_Semi-Supervised_Monocular_3D_Object_Detection_CVPR_2024_paper.html">Decoupled Pseudo-labeling for Semi-Supervised Monocular 3D Object Detection (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content_CVPRW_2020/html/w45/Rebuffi_Semi-Supervised_Learning_With_Scarce_Annotations_CVPRW_2020_paper.html">Semi-Supervised Learning With Scarce Annotations (2020)</a></li> <li><a href="https://openaccess.thecvf.com/content_CVPR_2020/html/Yang_Phase_Consistent_Ecological_Domain_Adaptation_CVPR_2020_paper.html">Phase Consistent Ecological Domain Adaptation (2020)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 4 - Domain Adaptation: Bridging the Gap Between Source and Target Domains (323 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_6.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 4" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Domain adaptation (DA) focuses on adapting models trained on a labeled source domain to perform well on an unseen target domain, addressing the challenges posed by domain shift or domain gap. This process is crucial when the source and target domains differ significantly, such as in cross-domain generalization tasks. Techniques like pseudo-labeling, self-training, and few-shot learning are employed to improve performance on target data, even when labeled data from the target domain is limited or unavailable. Domain adaptation methods aim to reduce the discrepancy between the source and target domains by minimizing the impact of domain shift and leveraging unlabeled target samples. These methods are vital for applications like visual domain adaptation, where new target domains with varying conditions or classes are frequently encountered. <br/> <br/> Top authors: <ol> <li>Luc Van Gool (8 papers)</li> <li>Dengxin Dai (7 papers)</li> <li>Wen Li (7 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2021W/WiCV/html/Thota_Contrastive_Domain_Adaptation_CVPRW_2021_paper.html">Contrastive Domain Adaptation (2021)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2021W/LLID/html/Cai_DAMSL_Domain_Agnostic_Meta_Score-Based_Learning_CVPRW_2021_paper.html">DAMSL: Domain Agnostic Meta Score-Based Learning (2021)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2021/html/Song_Spatio-temporal_Contrastive_Domain_Adaptation_for_Action_Recognition_CVPR_2021_paper.html">Spatio-temporal Contrastive Domain Adaptation for Action Recognition (2021)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 5 - 3D Object Detection: Advancements in Lidar and Monocular Approaches for Autonomous Vehicles (217 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_15.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 5" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> 3D object detection is a critical component of autonomous driving, enabling vehicles to perceive and understand their environment in three dimensions. Using technologies like lidar, monocular cameras, and radar, 3D detection systems create detailed representations of the surroundings, often represented in formats such as birds-eye view (BEV) or voxel grids. Datasets like KITTI, NuScenes, and Waymo provide benchmarks for evaluating 3D detection models, with lidar-based point clouds playing a central role in high-accuracy detection of objects, such as pedestrians, vehicles, and obstacles. These systems face challenges such as slow inference speeds and the complexity of predicting occupancy grids, but advancements in lidar sensors, occupancy prediction, and BEV detectors are helping improve autonomous vehicle perception and safety. As autonomous driving systems evolve, 3D detection continues to be crucial for precise navigation and decision-making. <br/> <br/> Top authors: <ol> <li>Jie Zhou (7 papers)</li> <li>Jiwen Lu (6 papers)</li> <li>Yuexin Ma (6 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Li_GAFusion_Adaptive_Fusing_LiDAR_and_Camera_with_Multiple_Guidance_for_CVPR_2024_paper.html">GAFusion: Adaptive Fusing LiDAR and Camera with Multiple Guidance for 3D Object Detection (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Tang_SparseOcc_Rethinking_Sparse_Latent_Representation_for_Vision-Based_Semantic_Occupancy_Prediction_CVPR_2024_paper.html">SparseOcc: Rethinking Sparse Latent Representation for Vision-Based Semantic Occupancy Prediction (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Yin_IS-Fusion_Instance-Scene_Collaborative_Fusion_for_Multimodal_3D_Object_Detection_CVPR_2024_paper.html">IS-Fusion: Instance-Scene Collaborative Fusion for Multimodal 3D Object Detection (2024)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 6 - Weakly Supervised Object Segmentation: Balancing Annotations and Performance (244 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_13.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 6" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Weakly supervised object segmentation focuses on leveraging less detailed annotations, such as image-level labels or object proposals, to train segmentation models. Unlike fully supervised methods that require pixel-level annotations, weak supervision relies on class-level or bounding box labels to guide the segmentation process. Datasets like Pascal VOC and MS COCO provide benchmarks for evaluating segmentation models, with metrics such as mean Intersection over Union (mIoU) used to assess performance. Techniques like class-agnostic object masks, discriminative region mapping (CAM), and pseudo-masks are employed to generate pixel-level segmentations from weak annotations. This approach aims to reduce the cost and effort associated with obtaining high-quality, pixel-wise annotations, while still achieving competitive segmentation results, especially for complex tasks like instance-level segmentation and object part identification. <br/> <br/> Top authors: <ol> <li>Junwei Han (5 papers)</li> <li>Yunchao Wei (5 papers)</li> <li>Bingfeng Zhang (4 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content_CVPR_2020/html/Cheng_CascadePSP_Toward_Class-Agnostic_and_Very_High-Resolution_Segmentation_via_Global_and_CVPR_2020_paper.html">CascadePSP: Toward Class-Agnostic and Very High-Resolution Segmentation via Global and Local Refinement (2020)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2023/html/Huynh_SimpSON_Simplifying_Photo_Cleanup_With_Single-Click_Distracting_Object_Segmentation_Network_CVPR_2023_paper.html">SimpSON: Simplifying Photo Cleanup With Single-Click Distracting Object Segmentation Network (2023)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2023/html/Kang_Distilling_Self-Supervised_Vision_Transformers_for_Weakly-Supervised_Few-Shot_Classification__Segmentation_CVPR_2023_paper.html">Distilling Self-Supervised Vision Transformers for Weakly-Supervised Few-Shot Classification &amp; Segmentation (2023)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 7 - Image Relighting: Enhancing Lighting and Material Effects in Digital Rendering (167 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_21.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 7" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Image relighting is a technique used in computer graphics and computational photography to manipulate or simulate changes in lighting conditions on a given scene or object. This process involves adjusting various aspects of lighting, such as specular and diffuse reflections, albedo, and shadow effects, to create realistic or desired lighting outcomes. It takes into account material properties like reflectance, illumination, and surface normals, which determine how light interacts with the scene. Relighting is commonly applied in tasks such as portrait or face relighting, where the goal is to alter lighting without changing the geometry of the scene. By estimating and adjusting lighting effects like specular highlights, shadows, and ambient light, image relighting allows for enhanced visual realism and flexibility in various applications, from film production to virtual environments and interactive systems. <br/> <br/> Top authors: <ol> <li>Boxin Shi (11 papers)</li> <li>Kalyan Sunkavalli (7 papers)</li> <li>Noah Snavely (6 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content_cvpr_2018/html/Mo_Uncalibrated_Photometric_Stereo_CVPR_2018_paper.html">Uncalibrated Photometric Stereo Under Natural Illumination (2018)</a></li> <li><a href="https://openaccess.thecvf.com/content_CVPR_2020/html/Thapa_Dynamic_Fluid_Surface_Reconstruction_Using_Deep_Neural_Network_CVPR_2020_paper.html">Dynamic Fluid Surface Reconstruction Using Deep Neural Network (2020)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2021/html/R_Monocular_Reconstruction_of_Neural_Face_Reflectance_Fields_CVPR_2021_paper.html">Monocular Reconstruction of Neural Face Reflectance Fields (2021)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 8 - Large Kernel Convolutions and Self-Attention Mechanisms in Vision Transformers (209 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_16.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 8" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> The integration of large kernel convolutions and self-attention mechanisms has become a powerful approach in modern computer vision tasks. Large kernel convolutions, such as atrous or depthwise convolutions, allow for an increased receptive field, enabling the model to capture long-range dependencies in an image without significantly increasing computational cost. This is essential for vision tasks like object detection and segmentation, where understanding the global context is crucial. On the other hand, self-attention mechanisms, particularly in Vision Transformers (ViTs), facilitate capturing relationships between distant image patches, enhancing the model's ability to focus on relevant parts of an image. By combining large kernel convolutions with self-attention layers, models like the Vision Transformer (ViT) can effectively balance local feature extraction and global context understanding, leading to improved performance on benchmarks like ADE, Cityscapes, and COCO, especially in tasks like segmentation and scene understanding. This combination provides an efficient and scalable solution for handling complex vision tasks while maintaining competitive performance. <br/> <br/> Top authors: <ol> <li>Xiangyu Zhang (6 papers)</li> <li>Chang Xu (5 papers)</li> <li>Yu Qiao (5 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2022/html/Zhang_PatchFormer_An_Efficient_Point_Transformer_With_Patch_Attention_CVPR_2022_paper.html">PatchFormer: An Efficient Point Transformer With Patch Attention (2022)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2024/html/Ding_UniRepLKNet_A_Universal_Perception_Large-Kernel_ConvNet_for_Audio_Video_Point_CVPR_2024_paper.html">UniRepLKNet: A Universal Perception Large-Kernel ConvNet for Audio Video Point Cloud Time-Series and Image Recognition (2024)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2021/html/Ruan_Gaussian_Context_Transformer_CVPR_2021_paper.html">Gaussian Context Transformer (2021)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 9 - 3D-Aware Image Synthesis with GANs for High-Fidelity and Controllable Rendering (71 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_91.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 9" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> 3D-aware image synthesis is an advanced technique that combines the power of Generative Adversarial Networks (GANs) with 3D geometry to create highly realistic and controllable images. By incorporating 3D-aware models like Neural Radiance Fields (NeRF) and leveraging latent spaces in GAN architectures such as StyleGAN, this method enables the generation of high-fidelity images from novel views or multi-view perspectives. This approach allows for fine-grained control over attributes like lighting, angles, and details, making it particularly useful for photorealistic rendering and editing. The synthesis process ensures that the generated images maintain consistency across different views and provide high-quality visual outputs, which can be applied in areas such as virtual reality, digital content creation, and computer graphics. With advancements in 3D-aware GANs, it is now possible to synthesize photo-realistic images with impressive fidelity, enabling novel applications in creative industries. <br/> <br/> Top authors: <ol> <li>Gordon Wetzstein (4 papers)</li> <li>Jiajun Wu (4 papers)</li> <li>Sida Peng (4 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2023/html/Xu_DisCoScene_Spatially_Disentangled_Generative_Radiance_Fields_for_Controllable_3D-Aware_Scene_CVPR_2023_paper.html">DisCoScene: Spatially Disentangled Generative Radiance Fields for Controllable 3D-Aware Scene Synthesis (2023)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2023/html/Kim_NeuralField-LDM_Scene_Generation_With_Hierarchical_Latent_Diffusion_Models_CVPR_2023_paper.html">NeuralField-LDM: Scene Generation With Hierarchical Latent Diffusion Models (2023)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2023/html/Li_Lift3D_Synthesize_3D_Training_Data_by_Lifting_2D_GAN_to_CVPR_2023_paper.html">Lift3D: Synthesize 3D Training Data by Lifting 2D GAN to 3D Generative Radiance Field (2023)</a></li> </ul> <hr/> </details> <details> <summary><b>Topic 10 - Efficient Solving of Non-Convex Problems with Outlier Rejection and Relaxation Techniques (356 documents)</b></summary> <figure> <picture> <img src="/assets/img/blog/2025-03-26-cvpr-history-analysis/topic_4.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" alt="Wordcloud for topic 10" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> Solving non-convex problems, especially those involving outlier detection, correspondence, and registration, is a complex challenge in fields like computer vision and robotics. Methods like RANSAC (Random Sample Consensus) and polynomial solvers are commonly used to handle these issues, where outliers — incorrect data points — are filtered out to improve the accuracy of the solution. Convex relaxation techniques and non-convex optimization solvers are applied to iteratively refine the solution toward a globally optimal result. For example, pose estimation problems, such as relative rotation or translation, are solved efficiently by leveraging convex optimization and minimal solvers, ensuring that even with noisy or incomplete data, the solution converges to the correct answer. These techniques, including the use of least squares and graph matching, play a key role in ensuring robust performance in real-world applications, where noise and outliers are unavoidable. <br/> <br/> Top authors: <ol> <li>Daniel Barath (13 papers)</li> <li>Daniel Cremers (13 papers)</li> <li>Viktor Larsson (10 papers)</li> </ol> Example papers: <ul> <li><a href="https://openaccess.thecvf.com/content/CVPR2023/html/Bai_Sliced_Optimal_Partial_Transport_CVPR_2023_paper.html">Sliced Optimal Partial Transport (2023)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2023/html/Zhang_3D_Registration_With_Maximal_Cliques_CVPR_2023_paper.html">3D Registration With Maximal Cliques (2023)</a></li> <li><a href="https://openaccess.thecvf.com/content/CVPR2023/html/He_A_Rotation-Translation-Decoupled_Solution_for_Robust_and_Efficient_Visual-Inertial_Initialization_CVPR_2023_paper.html">A Rotation-Translation-Decoupled Solution for Robust and Efficient Visual-Inertial Initialization (2023)</a></li> </ul> <hr/> </details> <h2 id="conclusion">Conclusion</h2> <p>In this analysis, we have explored the trends and shifts in research topics within the CVPR community over the past years. The data reveals a dynamic landscape, with certain areas experiencing significant growth while others have seen a decline in interest. This reflects the evolving nature of artificial intelligence research and the continuous pursuit of innovation and improvement in various domains.</p> <p>The hottest topics — ranging from instruction-tuned multimodal LLMs for vision-language understanding to the rapid advancements in text-guided editing, 3D-aware synthesis, and event-based vision — highlight a strong drive toward bridging modalities, creating more controllable generative models, and addressing the growing needs of real-world applications. Researchers are increasingly focusing on improving the integration of language and vision to enable more effective reasoning, better handling of ambiguities (such as hallucinations), and enhanced performance in both creative and safety-critical environments.</p> <p>In contrast, the coldest topics — such as self-supervised pretraining, traditional vision-language alignment, semi-supervised learning, domain adaptation, and even classical 3D object detection — indicate areas where mature techniques have plateaued. While these methods laid the foundations for current advances, their rate of improvement appears to have slowed in favor of newer approaches. Techniques once at the cutting edge are now being revisited with an eye toward integrating them into more comprehensive systems, but their standalone appeal is declining as the community shifts toward end-to-end, multimodal, and task-specific solutions.</p> <p>Taken together, the trends suggest that the field is steering toward more holistic, integrated models that not only push the boundaries of what automated systems can generate or analyze but also provide greater reliability and control in real-world applications. As the industry continues to explore the fusion of text, image, and even sensor data, the next wave of innovation will likely be driven by systems that learn from multiple modalities concurrently — while leveraging long-standing, robust principles as a stepping stone.</p> <p>This evolution underscores the vibrant nature of artificial intelligence research, where established methods provide a stable base while emerging techniques hold the promise of reshaping the future of artificial intelligence.</p>]]></content><author><name></name></author><category term="data-science"/><category term="ai"/><category term="conference"/><category term="analysis"/><summary type="html"><![CDATA[A look at the history of CVPR and its workshops from 2017 to 2024.]]></summary></entry><entry><title type="html">sli.dev for non-web developers</title><link href="https://george-gca.github.io/blog/2023/slidev_for_non_web_devs/" rel="alternate" type="text/html" title="sli.dev for non-web developers"/><published>2023-06-01T17:19:10+00:00</published><updated>2023-06-01T17:19:10+00:00</updated><id>https://george-gca.github.io/blog/2023/slidev_for_non_web_devs</id><content type="html" xml:base="https://george-gca.github.io/blog/2023/slidev_for_non_web_devs/"><![CDATA[<p>I always struggled every time I had to do a new presentation. Don’t get me wrong, Google Slides is good, and suffices for most common use cases. The problem is when the slides keeps changing, and you want to do some versioning on them. I made some slides in the past using LaTeX with the Beamer class. A friend even showed me a <a href="https://github.com/deuslirio/UFGTeX-Presentation">nicer template</a> than the default ones. The problem is, though this solution is portable (you can generate a PDF file), it lacks some features that I wanted, like animations, transitions, and support for drawing.</p> <p>I took a look at <a href="https://revealjs.com/">Reveal.js</a>, but it was too much work to setup and maintain. I also went for <a href="https://remarkjs.com/">Remark</a>, but the <a href="https://github.com/gnab/remark">last update</a> was more than 2 years ago. That’s when I found <a href="https://sli.dev/">sli.dev</a>. It’s a framework <a href="https://github.com/slidevjs/slidev">under constant development</a> for creating slides using <a href="https://sli.dev/guide/syntax.html">Markdown</a>. It’s based on a lot of web technologies, but you don’t need to be fluent on them to use it. Here is everything that you’ll need to get started.</p> <h2 id="installing-node-version-manager-nvm">Installing node version manager (nvm)</h2> <p><a href="https://github.com/nvm-sh/nvm">nvm</a> allows you to quickly install and use different versions of node via the command line. To install the latest version, run the following command:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>get_latest_github_raw_no_v<span class="o">()</span> <span class="o">{</span>
  <span class="c"># use it for when the link for the download doesn't have a version included in the name of the file</span>
  <span class="c"># e.g.: https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh</span>
  <span class="c"># usage: get_latest_github_raw_no_v "user/repo" "filename"</span>
  <span class="nv">version</span><span class="o">=</span><span class="si">$(</span>curl <span class="nt">--silent</span> <span class="s2">"https://api.github.com/repos/</span><span class="nv">$1</span><span class="s2">/releases/latest"</span> |  <span class="c"># Get latest release from GitHub api</span>
    <span class="nb">grep</span> <span class="s1">'"tag_name":'</span> |                                             <span class="c"># Get tag line</span>
    <span class="nb">sed</span> <span class="nt">-E</span> <span class="s1">'s/.*"([^"]+)".*/\1/'</span><span class="si">)</span>                                    <span class="c"># Pluck JSON value</span>
  <span class="nb">echo</span> <span class="s2">"https://raw.githubusercontent.com/</span><span class="nv">$1</span><span class="s2">/</span><span class="nv">$version</span><span class="s2">/"</span><span class="nv">$2</span>
<span class="o">}</span>

<span class="c"># Install node version manager (nvm)</span>
<span class="nv">site</span><span class="o">=</span><span class="si">$(</span>get_latest_github_raw_no_v <span class="s2">"nvm-sh/nvm"</span> <span class="s2">"install.sh"</span><span class="si">)</span>
curl <span class="nt">-o-</span> <span class="nv">$site</span> | bash
</code></pre></div></div> <p>Then, add the following lines to your <code class="language-plaintext highlighter-rouge">~/.bashrc</code> file:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># enable node version manager</span>
<span class="k">if</span> <span class="o">[</span> <span class="nt">-d</span> <span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.nvm"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">export </span><span class="nv">NVM_DIR</span><span class="o">=</span><span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.nvm"</span>
    <span class="o">[</span> <span class="nt">-s</span> <span class="s2">"</span><span class="nv">$NVM_DIR</span><span class="s2">/nvm.sh"</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\.</span> <span class="s2">"</span><span class="nv">$NVM_DIR</span><span class="s2">/nvm.sh"</span>  <span class="c"># This loads nvm</span>
    <span class="o">[</span> <span class="nt">-s</span> <span class="s2">"</span><span class="nv">$NVM_DIR</span><span class="s2">/bash_completion"</span> <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\.</span> <span class="s2">"</span><span class="nv">$NVM_DIR</span><span class="s2">/bash_completion"</span>  <span class="c"># This loads nvm bash_completion</span>
<span class="k">fi</span>
</code></pre></div></div> <p>Restart your terminal, or just reload the <code class="language-plaintext highlighter-rouge">~/.bashrc</code> file:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">.</span> ~/.bashrc
</code></pre></div></div> <h2 id="installing-node-latest-version">Installing Node (latest version)</h2> <p>To install the latest node version, run the following command:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nvm <span class="nb">install</span> <span class="si">$(</span>nvm ls-remote | <span class="nb">grep</span> <span class="nt">-i</span> latest | <span class="nb">tail</span> <span class="nt">-n</span> 1 |
  <span class="nb">sed</span> <span class="nt">-ne</span> <span class="s1">'s/[^v0-9]*\(\([0-9]*\.\)\{0,4\}[0-9][^.]\).*/\1/p'</span> | xargs<span class="si">)</span>
</code></pre></div></div> <p>In my case, the latest version available is <code class="language-plaintext highlighter-rouge">v20.2.0</code>. You can check the installed version by running:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>node <span class="nt">--version</span>
</code></pre></div></div> <h2 id="installing-slidev">Installing sli.dev</h2> <p>To install sli.dev, simply run:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm init slidev
</code></pre></div></div> <p>This command will install everything you need, ask for the project name, and start the template project. After the installation, you should see the following lines in your terminal:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>public slide show   &gt; http://localhost:3030/
  presenter mode      &gt; http://localhost:3030/presenter/
  remote control      &gt; pass --remote to enable

  shortcuts           &gt; restart | open | edit
</code></pre></div></div> <p>If the browser did not open automatically, you can open it manually by accessing the URL <code class="language-plaintext highlighter-rouge">http://localhost:3030/</code>. To stop running the server, just press <code class="language-plaintext highlighter-rouge">Ctrl+C</code> in the terminal. After stopped, you can start the development server again by entering the created directory and running:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm run-script dev
</code></pre></div></div> <p>To see a list of scripts, run <code class="language-plaintext highlighter-rouge">npm run</code>:</p> <pre><code class="language-txt">Scripts available in XXXXXXXXX via `npm run-script`:
  build
    slidev build
  dev
    slidev --open
  export
    slidev export
</code></pre> <p>If you want to modify any of these commands (or create more, like exporting presenter notes), you can edit the <code class="language-plaintext highlighter-rouge">package.json</code> file. For example, to add a command to export presenter notes, add the following lines to the <code class="language-plaintext highlighter-rouge">scripts</code> section:</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"export_notes"</span><span class="p">:</span><span class="w"> </span><span class="s2">"slidev export-notes"</span><span class="w">
</span></code></pre></div></div> <h2 id="changing-slidev-template">Changing sli.dev template</h2> <p>You can change the presentation theme simply by editing the <code class="language-plaintext highlighter-rouge">theme</code> attribute on the <a href="https://sli.dev/guide/syntax.html#front-matter-layouts">front matter</a> of <code class="language-plaintext highlighter-rouge">slides.md</code> file. When you change and save it, the cli interface will automatically download and apply the new theme.</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">theme</span><span class="pi">:</span> <span class="s">academic</span>
</code></pre></div></div> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/blog/2023-06-01-slidev_for_non_web_devs/change_theme-480.webp 480w,/assets/img/blog/2023-06-01-slidev_for_non_web_devs/change_theme-800.webp 800w,/assets/img/blog/2023-06-01-slidev_for_non_web_devs/change_theme-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/blog/2023-06-01-slidev_for_non_web_devs/change_theme.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <div class="caption"> sli.dev installing new theme. </div> <h2 id="basic-settings">Basic settings</h2> <p>I am not a hardcore sli.dev user or web developer. So there were some things that took some time for me to figure out, and I think it is worth mentioning. The first one is forcing the slides to be in dark mode. To do that, add the following line to the front matter of <code class="language-plaintext highlighter-rouge">slides.md</code>:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">colorSchema</span><span class="pi">:</span> <span class="s2">"</span><span class="s">dark"</span>
</code></pre></div></div> <p>While using the <code class="language-plaintext highlighter-rouge">academic</code> theme, by default every slide with a <code class="language-plaintext highlighter-rouge"># title</code> will be added to the table of contents. To hide a slide from the table of contents, add the following line to the front matter of the slide:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">hideInToc</span><span class="pi">:</span> <span class="kc">true</span>
</code></pre></div></div> <p>For the sake of organization, I like to create a different file for each section in my presentation, then import these files in my main <code class="language-plaintext highlighter-rouge">slides.md</code>. To do that, create a new file with the markdown extension, then add the following lines to <code class="language-plaintext highlighter-rouge">slides.md</code> for each file to be included:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="na">src</span><span class="pi">:</span> <span class="s">slides/other_slide.md</span>
<span class="nn">---</span>
</code></pre></div></div> <h2 id="exporting-slides">Exporting slides</h2> <p><a href="https://sli.dev/guide/exporting.html">Exporting to PDF or PNG</a> relies on <code class="language-plaintext highlighter-rouge">Playwright</code> for rendering. You will therefore need to install <code class="language-plaintext highlighter-rouge">playwright-chromium</code> to use this feature. For this, run:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm i <span class="nt">-D</span> playwright-chromium
</code></pre></div></div> <p>Then, add the following lines to the <code class="language-plaintext highlighter-rouge">scripts</code> section of the <code class="language-plaintext highlighter-rouge">package.json</code> file:</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nl">"export_slides"</span><span class="p">:</span><span class="w"> </span><span class="s2">"slidev export --with-toc --with-clicks"</span><span class="w">
</span></code></pre></div></div> <p>To export the slides, run:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm run-script export_slides
</code></pre></div></div> <h2 id="updating-dependencies">Updating dependencies</h2> <p>To update <code class="language-plaintext highlighter-rouge">node</code> to the latest LTS release, run:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nvm <span class="nb">install</span> <span class="si">$(</span>nvm ls-remote | <span class="nb">grep</span> <span class="nt">-i</span> latest | <span class="nb">tail</span> <span class="nt">-n</span> 1 |
  <span class="nb">sed</span> <span class="nt">-ne</span> <span class="s1">'s/[^v0-9]*\(\([0-9]*\.\)\{0,4\}[0-9][^.]\).*/\1/p'</span> | xargs<span class="si">)</span> <span class="nt">--reinstall-packages-from</span><span class="o">=</span>current
</code></pre></div></div> <p>To check for dependencies that need to be updated, run:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm outdated
</code></pre></div></div> <p>which will output something like this:</p> <pre><code class="language-txt">Package      Current   Wanted  Latest  Location                  Depended by
@slidev/cli  0.43.11  0.43.15  0.46.1  node_modules/@slidev/cli  xxxxxxxx
</code></pre> <p>To updated installed dependencies, simply run:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm update
</code></pre></div></div> <p>Keep in mind that <code class="language-plaintext highlighter-rouge">npm update</code> will never update to a major breaking-changes version, only to a minor one. What this means is, it will use the <code class="language-plaintext highlighter-rouge">Wanted</code> version in the table above instead of the <code class="language-plaintext highlighter-rouge">Latest</code> version. To obtain the <code class="language-plaintext highlighter-rouge">Latest</code> version, call the install command with <code class="language-plaintext highlighter-rouge">@latest</code> appended to the package name. For example, to update <code class="language-plaintext highlighter-rouge">@slidev/cli</code> to the latest version, run:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm <span class="nb">install</span> @slidev/cli@latest
</code></pre></div></div>]]></content><author><name></name></author><category term="web"/><category term="presentation"/><category term="programming"/><category term="code"/><category term="slides"/><category term="sli.dev"/><category term="web"/><summary type="html"><![CDATA[How to setup and use sli.dev for non-web developers]]></summary></entry><entry><title type="html">Improving your python code with simple tricks</title><link href="https://george-gca.github.io/blog/2023/simple-improvements-python-code/" rel="alternate" type="text/html" title="Improving your python code with simple tricks"/><published>2023-01-25T13:28:15+00:00</published><updated>2023-01-25T13:28:15+00:00</updated><id>https://george-gca.github.io/blog/2023/simple-improvements-python-code</id><content type="html" xml:base="https://george-gca.github.io/blog/2023/simple-improvements-python-code/"><![CDATA[<p>Sometimes our code is running slow. Sometimes it is eating up memory. Maybe it is just not as readable as we would like it to be. In this post, we will see how to use some functions from the default library to improve our code. All the code used in this post <a href="https://gist.github.com/george-gca/bea9d8c23a0932a22d6b1b80006629f4">is available here</a>. While I only presented a few functions that I use frequently, there are many more that can be used to improve your code. I encourage you to check the <a href="https://docs.python.org/3/library/">official documentation</a> to see what else is available.</p> <h2 id="use-list-comprehension-whenever-possible">Use <a href="https://realpython.com/list-comprehension-python/">list comprehension</a> whenever possible</h2> <h3 id="what-does-it-mean">What does it mean?</h3> <p>List comprehension is basically another way to create a list. Suppose we want to create a list from values in a range:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># traditional way
</span><span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">):</span>
  <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>

<span class="c1"># list comprehension
</span><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)]</span>
</code></pre></div></div> <h3 id="why-does-it-matter">Why does it matter?</h3> <p>List comprehension is usually much faster than the traditional loop. Let’s compare them:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">):</span>
  <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">1.04 s ± 89.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 293.57 MiB
</code></pre> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)]</span>
</code></pre></div></div> <pre><code class="language-txt">731 ms ± 71.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 285.82 MiB
</code></pre> <h3 id="other-examples">Other examples</h3> <h4 id="creating-a-list-with-an-if-condition">Creating a list with an <code class="language-plaintext highlighter-rouge">if</code> condition</h4> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">):</span>
  <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
    <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">1.11 s ± 24 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: -0.25 MiB
</code></pre> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)</span> <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">]</span>
</code></pre></div></div> <pre><code class="language-txt">944 ms ± 6.79 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 115.54 MiB
</code></pre> <hr/> <h4 id="creating-a-list-with-an-if-else-condition">Creating a list with an <code class="language-plaintext highlighter-rouge">if else</code> condition</h4> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">):</span>
  <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
    <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
  <span class="k">else</span><span class="p">:</span>
    <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">1.61 s ± 90.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 32.89 MiB
</code></pre> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)]</span>
</code></pre></div></div> <pre><code class="language-txt">1.33 s ± 11.4 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 273.82 MiB
</code></pre> <h3 id="fastest-way-to-create-a-list">Fastest way to create a list</h3> <p>When generating a list from a generator (<code class="language-plaintext highlighter-rouge">range</code> in this case), it is even faster to use the <code class="language-plaintext highlighter-rouge">list()</code> constructor.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">))</span>
</code></pre></div></div> <p>To validate this, let’s compare the code for 7 runs, 10 loops each:</p> <table> <thead> <tr> <th style="text-align: center"> </th> <th style="text-align: center">loop</th> <th style="text-align: center">list comprehension</th> <th style="text-align: center">list constructor</th> </tr> </thead> <tbody> <tr> <td style="text-align: center">mean ± std. dev. per loop</td> <td style="text-align: center">1.04 s ± 89.8 ms</td> <td style="text-align: center">731 ms ± 71.6 ms</td> <td style="text-align: center">301 ms ± 18.4 ms</td> </tr> <tr> <td style="text-align: center">memory increment</td> <td style="text-align: center">293.57 MiB</td> <td style="text-align: center">285.82 MiB</td> <td style="text-align: center">75.12 MiB</td> </tr> </tbody> </table> <p>Why is the <code class="language-plaintext highlighter-rouge">list()</code> constructor faster? According to <a href="https://stackoverflow.com/a/29356931">this answer in StackOverflow</a>:</p> <blockquote> <p>The list comprehension executes the loop in Python bytecode, just like a regular for loop. The list() call iterates entirely in C code, which is far faster.</p> </blockquote> <p>To compare all these solutions, lets check the equivalent bytecodes. For the loop solution:</p> <pre><code class="language-txt">1           0 BUILD_LIST               0
            2 STORE_NAME               0 (tmp)

2           4 LOAD_NAME                1 (range)
            6 LOAD_CONST               0 (10000000)
            8 CALL_FUNCTION            1
            10 GET_ITER
    &gt;&gt;   12 FOR_ITER                14 (to 28)
            14 STORE_NAME               2 (i)
            16 LOAD_NAME                0 (tmp)
            18 LOAD_METHOD              3 (append)
            20 LOAD_NAME                2 (i)
            22 CALL_METHOD              1
            24 POP_TOP
            26 JUMP_ABSOLUTE           12
    &gt;&gt;   28 LOAD_CONST               1 (None)
            30 RETURN_VALUE
</code></pre> <p>For the list comprehension solution:</p> <pre><code class="language-txt">1           0 LOAD_CONST               0 (&lt;code object &lt;listcomp&gt; at 0x7f272c8eaf50, file "&lt;stdin&gt;", line 1&gt;)
            2 LOAD_CONST               1 ('&lt;listcomp&gt;')
            4 MAKE_FUNCTION            0
            6 LOAD_NAME                0 (range)
            8 LOAD_NAME                1 (10_000_000)
            10 CALL_FUNCTION            1
            12 GET_ITER
            14 CALL_FUNCTION            1
            16 POP_TOP
            18 LOAD_CONST               2 (None)
            20 RETURN_VALUE

Disassembly of &lt;code object &lt;listcomp&gt; at 0x7f272c8eaf50, file "&lt;stdin&gt;", line 1&gt;:
1           0 BUILD_LIST               0
            2 LOAD_FAST                0 (.0)
    &gt;&gt;    4 FOR_ITER                 8 (to 14)
            6 STORE_FAST               1 (i)
            8 LOAD_FAST                1 (i)
            10 LIST_APPEND              2
            12 JUMP_ABSOLUTE            4
    &gt;&gt;   14 RETURN_VALUE
</code></pre> <p>And for the list constructor solution:</p> <pre><code class="language-txt">1           0 LOAD_NAME                0 (list)
            2 LOAD_NAME                1 (range)
            4 LOAD_NAME                2 (10_000_000)
            6 CALL_FUNCTION            1
            8 CALL_FUNCTION            1
            10 POP_TOP
            12 LOAD_CONST               0 (None)
            14 RETURN_VALUE
</code></pre> <p>We can see that the <code class="language-plaintext highlighter-rouge">list()</code> constructor generates less bytecodes.</p> <h2 id="use-generators-and-iterators-whenever-possible">Use <a href="https://realpython.com/introduction-to-python-generators/">generators</a> and <a href="https://docs.python.org/3/glossary.html#term-iterator">iterators</a> whenever possible</h2> <p>To create a generator like a list comprehension (called <a href="https://docs.python.org/3/glossary.html#index-20">generator expression</a>), just replace the squared brackets [ ] with parenthesis ( ).</p> <h3 id="why-does-it-matter-1">Why does it matter?</h3> <p><a href="https://docs.python.org/3/glossary.html#index-19">Generators</a> looks like a normal function, except that it contains <code class="language-plaintext highlighter-rouge">yield</code> expressions for producing a series of values usable in a for-loop or that can be retrieved one at a time with the <code class="language-plaintext highlighter-rouge">next()</code> function. It returns a <a href="https://docs.python.org/3/glossary.html#term-generator-iterator">generator iterator</a>, which temporarily suspends processing, remembering the location execution state (including local variables and pending try-statements).</p> <p>Let’s do some comparisons:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">([</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)])</span>
</code></pre></div></div> <pre><code class="language-txt">860 ms ± 30.4 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
</code></pre> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">((</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)))</span>
</code></pre></div></div> <pre><code class="language-txt">609 ms ± 2.93 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
</code></pre> <p>Not that different right? Now, let’s check the memory usage. Let’s focus on increment, since it represents the difference in memory between the beginning and end of this execution.</p> <pre><code class="language-txt">memory increment: 263.44 MiB
</code></pre> <pre><code class="language-txt">memory increment: 0.00 MiB
</code></pre> <p>What happened? The generator only returns one element at a time, which is given to the sum function. This way, we don’t need to pre-generate the whole list to perform the sum of the elements. In fact, since the <a href="https://docs.python.org/3/library/functions.html#sum">sum</a> function gets an iterator as parameter, we could call it like this:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">))</span>
</code></pre></div></div> <pre><code class="language-txt">593 ms ± 90.4 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.01 MiB
</code></pre> <p>Or even:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">))</span>
</code></pre></div></div> <pre><code class="language-txt">168 ms ± 4.68 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.00 MiB
</code></pre> <p>Which runs way faster.</p> <h2 id="avoid-generating-all-the-values-whenever-possible">Avoid generating all the values whenever possible</h2> <p>For the sake of these examples, suppose we have an ordered list of values.</p> <h3 id="what-to-do-if-we-want-only-the-values-lower-than-a-limit">What to do if we want only the values lower than a limit?</h3> <p>The list comprehension way of achieving this is this:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)</span> <span class="k">if</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">1_000_000</span><span class="p">]</span>
</code></pre></div></div> <pre><code class="language-txt">596 ms ± 7.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.02 MiB
</code></pre> <p>Now, with loops:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">):</span>
  <span class="k">if</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">1_000_000</span><span class="p">:</span>
    <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
  <span class="k">else</span><span class="p">:</span>
    <span class="k">break</span>
</code></pre></div></div> <pre><code class="language-txt">116 ms ± 2.37 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.01 MiB
</code></pre> <p>Why is it faster with loops?</p> <p>Because using list comprehension, the whole list must be generated before selecting the elements. The same is not true for the loop, that only runs through some of the values.</p> <h3 id="can-we-do-better">Can we do better?</h3> <p>Yes, with <a href="https://docs.python.org/3/library/itertools.html#itertools.takewhile">takewhile</a>.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">itertools</span> <span class="kn">import</span> <span class="n">takewhile</span>

<span class="n">tmp</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">takewhile</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="mi">1_000_000</span><span class="p">,</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)))</span>
</code></pre></div></div> <pre><code class="language-txt">107 ms ± 2.37 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.01 MiB
</code></pre> <hr/> <p>Note: <code class="language-plaintext highlighter-rouge">takewhile</code> is only faster when you know that the condition will be satisfied “soon enough”.</p> <hr/> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">):</span>
  <span class="k">if</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">9_000_000</span><span class="p">:</span>
    <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
  <span class="k">else</span><span class="p">:</span>
    <span class="k">break</span>
</code></pre></div></div> <pre><code class="language-txt">1.12 s ± 27.5 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 3.70 MiB
</code></pre> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)</span> <span class="k">if</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">9_000_000</span><span class="p">]</span>
</code></pre></div></div> <pre><code class="language-txt">1.05 s ± 51 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 246.21 MiB
</code></pre> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">takewhile</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="mi">9_000_000</span><span class="p">,</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)))</span>
</code></pre></div></div> <pre><code class="language-txt">1.06 s ± 8.41 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.00 MiB
</code></pre> <p>In this case it is quicker to generate the whole list, and then filter it. But note, while using list comprehension is quicker, <code class="language-plaintext highlighter-rouge">takewhile</code> takes less memory, since it still doesn’t need to store the whole list, even momentarily.</p> <h3 id="what-if-we-want-only-the-values-higher-than-a-limit">What if we want only the values higher than a limit?</h3> <p>First, let’s try with loops:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">):</span>
  <span class="k">if</span> <span class="n">i</span> <span class="o">&gt;</span> <span class="mi">1_000_000</span><span class="p">:</span>
    <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">1.3 s ± 93.3 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.15 MiB
</code></pre> <p>Now, with list comprehension:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)</span> <span class="k">if</span> <span class="n">i</span> <span class="o">&gt;</span> <span class="mi">1_000_000</span><span class="p">]</span>
</code></pre></div></div> <pre><code class="language-txt">978 ms ± 11.2 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 169.84 MiB
</code></pre> <p>In this case, since the loop will run through every element, it is slower than the list comprehension. It takes less memory though, since it doesn’t need to store the whole list in memory.</p> <h3 id="can-we-do-better-1">Can we do better?</h3> <p>Yes, with <a href="https://docs.python.org/3/library/itertools.html#itertools.dropwhile">dropwhile</a>.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">itertools</span> <span class="kn">import</span> <span class="n">dropwhile</span>

<span class="n">tmp</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">dropwhile</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="mi">1_000_000</span><span class="p">,</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)))</span>
</code></pre></div></div> <pre><code class="language-txt">442 ms ± 10.2 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.05 MiB
</code></pre> <hr/> <p>Note: <code class="language-plaintext highlighter-rouge">dropwhile</code> also is only faster when you know that the condition will be satisfied “soon enough”.</p> <hr/> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">):</span>
  <span class="k">if</span> <span class="n">i</span> <span class="o">&gt;</span> <span class="mi">9_000_000</span><span class="p">:</span>
    <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">654 ms ± 9.3 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.00 MiB
</code></pre> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)</span> <span class="k">if</span> <span class="n">i</span> <span class="o">&gt;</span> <span class="mi">9_000_000</span><span class="p">]</span>
</code></pre></div></div> <pre><code class="language-txt">623 ms ± 13.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.01 MiB
</code></pre> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">dropwhile</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="mi">9_000_000</span><span class="p">,</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)))</span>
</code></pre></div></div> <pre><code class="language-txt">924 ms ± 104 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.01 MiB
</code></pre> <h3 id="what-about-when-we-want-to-get-the-first-n-samples">What about when we want to get the first N samples?</h3> <p>With loops:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">n</span><span class="p">,</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)):</span>
  <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">1_000_000</span><span class="p">:</span>
    <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
  <span class="k">else</span><span class="p">:</span>
    <span class="k">break</span>
</code></pre></div></div> <pre><code class="language-txt">147 ms ± 3.09 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.00 MiB
</code></pre> <p>Doing it with list comprehension:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)][:</span><span class="mi">1_000_000</span><span class="p">]</span>
</code></pre></div></div> <pre><code class="language-txt">523 ms ± 10.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.01 MiB
</code></pre> <p>Why is it faster with loops?</p> <p>Because using list comprehension, the whole list must be generated before doing the slice operation. The same is not true for the loop, that only runs through some of the values.</p> <h3 id="can-we-do-better-2">Can we do better?</h3> <p>Yes, with <a href="https://docs.python.org/3/library/itertools.html#itertools.islice">islice</a>.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">itertools</span> <span class="kn">import</span> <span class="n">islice</span>

<span class="n">tmp</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">islice</span><span class="p">((</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)),</span> <span class="mi">1_000_000</span><span class="p">))</span>
</code></pre></div></div> <pre><code class="language-txt">72.5 ms ± 1.82 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.01 MiB
</code></pre> <h3 id="what-about-when-we-want-to-get-the-last-n-samples">What about when we want to get the last N samples?</h3> <p>We can achieve the same result with <code class="language-plaintext highlighter-rouge">islice</code>. Let’s get straight to the comparisons:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">n</span><span class="p">,</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)):</span>
  <span class="k">if</span> <span class="n">n</span> <span class="o">&gt;</span> <span class="mi">9_000_000</span><span class="p">:</span>
    <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">1.44 s ± 95.3 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 0.00 MiB
</code></pre> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)][</span><span class="mi">9_000_000</span><span class="p">:]</span>
</code></pre></div></div> <pre><code class="language-txt">743 ms ± 8.52 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: 177.31 MiB
</code></pre> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">islice</span><span class="p">((</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">10_000_000</span><span class="p">)),</span> <span class="mi">9_000_000</span><span class="p">,</span> <span class="bp">None</span><span class="p">))</span>
</code></pre></div></div> <pre><code class="language-txt">796 ms ± 11.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
memory increment: -0.16 MiB
</code></pre> <hr/> <p>Note again that, as it happened with <code class="language-plaintext highlighter-rouge">dropwhile</code> when the condition takes longer to be satisfied, while using <code class="language-plaintext highlighter-rouge">islice</code> is slower than doing it with list comprehension, it takes much less memory.</p> <h3 id="what-if-we-just-want-to-count-the-number-of-elements-that-will-be-generated">What if we just want to count the number of elements that will be generated?</h3> <p>Suppose we want to know how many elements will be generated from a condition. Usually, we would do it like this:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="n">i</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">]</span>
<span class="n">count</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">1.02 s ± 63.6 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
increment: 0.04 MiB
</code></pre> <p>But the problem is, we are storing a whole list in memory only to get its length.</p> <h3 id="can-we-do-better-3">Can we do better?</h3> <p>Yes, by creating a generator that generates <code class="language-plaintext highlighter-rouge">1</code> every time the condition is true, and summing it.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">count</span> <span class="o">=</span> <span class="nf">sum</span><span class="p">(</span><span class="mi">1</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">991 ms ± 18.9 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
increment: 0.00 MiB
</code></pre> <h2 id="other-useful-itertools-functions">Other useful <a href="https://docs.python.org/3/library/itertools.html?highlight=itertools#module-itertools">itertools</a> functions</h2> <p>We already introduced 3 of the most useful functions: <code class="language-plaintext highlighter-rouge">dropwhile</code>, <code class="language-plaintext highlighter-rouge">islice</code>, and <code class="language-plaintext highlighter-rouge">takewhile</code>. Let’s check other useful functions.</p> <h3 id="cycle"><a href="https://docs.python.org/3/library/itertools.html?highlight=itertools#itertools.cycle">cycle</a></h3> <p>Repeats indefinitely a given sequence.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">itertools</span> <span class="kn">import</span> <span class="n">cycle</span>

<span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>

<span class="k">for</span> <span class="n">counter</span><span class="p">,</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="nf">cycle</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="mi">4</span><span class="p">))):</span>
  <span class="k">if</span> <span class="n">counter</span> <span class="o">==</span> <span class="mi">10</span><span class="p">:</span>
    <span class="k">break</span>

  <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">[0, 1, 2, 3, 0, 1, 2, 3, 0, 1]
</code></pre> <h3 id="repeat"><a href="https://docs.python.org/3/library/itertools.html?highlight=itertools#itertools.repeat">repeat</a></h3> <p>Repeats indefinitely a given value, unless the <code class="language-plaintext highlighter-rouge">times</code> argument is specified.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">itertools</span> <span class="kn">import</span> <span class="n">repeat</span>

<span class="n">tmp</span> <span class="o">=</span> <span class="nf">list</span><span class="p">(</span><span class="nf">repeat</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">5</span><span class="p">))</span>
<span class="nf">print</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">[10, 10, 10, 10, 10]
</code></pre> <h3 id="product"><a href="https://docs.python.org/3/library/itertools.html?highlight=itertools#itertools.product">product</a></h3> <p>Equivalent to a nested for-loop.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[]</span>

<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
  <span class="k">for</span> <span class="n">j</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
      <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
        <span class="n">tmp</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="nf">sum</span><span class="p">([</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">l</span><span class="p">]))</span>

<span class="nf">print</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">[0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4]
</code></pre> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">itertools</span> <span class="kn">import</span> <span class="n">product</span>

<span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="nf">sum</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">product</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="nf">range</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="nf">range</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="nf">range</span><span class="p">(</span><span class="mi">2</span><span class="p">))]</span>
<span class="nf">print</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">[0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4]
</code></pre> <p>Since in this case we are using the same sequence for all the loops, we can use <code class="language-plaintext highlighter-rouge">repeat</code> to simplify the code:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">itertools</span> <span class="kn">import</span> <span class="n">product</span>

<span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="nf">sum</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">product</span><span class="p">(</span><span class="nf">range</span><span class="p">(</span><span class="mi">2</span><span class="p">),</span> <span class="n">repeat</span><span class="o">=</span><span class="mi">4</span><span class="p">)]</span>
<span class="nf">print</span><span class="p">(</span><span class="n">tmp</span><span class="p">)</span>
</code></pre></div></div> <pre><code class="language-txt">[0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4]
</code></pre> <h3 id="itertools-has-all-the-combinatorics-functions-implemented"><a href="https://docs.python.org/3/library/itertools.html?highlight=itertools#module-itertools">itertools</a> has all the combinatorics functions implemented</h3> <table> <thead> <tr> <th style="text-align: center">product</th> <th style="text-align: center">permutation</th> <th style="text-align: center">combination w/ replacement</th> <th style="text-align: center">combination</th> </tr> </thead> <tbody> <tr> <td style="text-align: center">AA</td> <td style="text-align: center"> </td> <td style="text-align: center">AA</td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: center">AB</td> <td style="text-align: center">AB</td> <td style="text-align: center">AB</td> <td style="text-align: center">AB</td> </tr> <tr> <td style="text-align: center">AC</td> <td style="text-align: center">AC</td> <td style="text-align: center">AC</td> <td style="text-align: center">AC</td> </tr> <tr> <td style="text-align: center">AD</td> <td style="text-align: center">AD</td> <td style="text-align: center">AD</td> <td style="text-align: center">AD</td> </tr> <tr> <td style="text-align: center">BA</td> <td style="text-align: center">BA</td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: center">BB</td> <td style="text-align: center"> </td> <td style="text-align: center">BB</td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: center">BC</td> <td style="text-align: center">BC</td> <td style="text-align: center">BC</td> <td style="text-align: center">BC</td> </tr> <tr> <td style="text-align: center">BD</td> <td style="text-align: center">BD</td> <td style="text-align: center">BD</td> <td style="text-align: center">BD</td> </tr> <tr> <td style="text-align: center">CA</td> <td style="text-align: center">CA</td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: center">CB</td> <td style="text-align: center">CB</td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: center">CC</td> <td style="text-align: center"> </td> <td style="text-align: center">CC</td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: center">CD</td> <td style="text-align: center">CD</td> <td style="text-align: center">CD</td> <td style="text-align: center">CD</td> </tr> <tr> <td style="text-align: center">DA</td> <td style="text-align: center">DA</td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: center">DB</td> <td style="text-align: center">DB</td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: center">DC</td> <td style="text-align: center">DC</td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: center">DD</td> <td style="text-align: center"> </td> <td style="text-align: center">DD</td> <td style="text-align: center"> </td> </tr> </tbody> </table> <h2 id="improving-code-with-functools">Improving code with <a href="https://docs.python.org/3/library/functools.html?highlight=functools#module-functools">functools</a></h2> <h3 id="storing-function-calls-with-lru_cache">Storing function calls with <a href="https://docs.python.org/3/library/functools.html#functools.lru_cache">lru_cache</a></h3> <p>Let’s take the fibonacci function, for example, that calls itself recursively.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">n</span>
    <span class="k">return</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span>
</code></pre></div></div> <p>Let’s use it in a list comprehension to get the first 16 fibonacci numbers:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="nf">fib</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">16</span><span class="p">)]</span>
</code></pre></div></div> <pre><code class="language-txt">698 µs ± 152 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
</code></pre> <p>It takes a pretty good amount of time to execute for a small number. But what if we could automatically save the results of the previous calls to the function? That is what <code class="language-plaintext highlighter-rouge">lru_cache</code> is all about. It stores previous calls, with its given parameters and calculated output, as a least recent used (LRU) cache. This way, whenever we call the function and this call was already made (and its results are still stored in the cache), we simply get the results from the cache.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">functools</span> <span class="kn">import</span> <span class="n">lru_cache</span>

<span class="nd">@lru_cache</span>
<span class="k">def</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="k">if</span> <span class="n">n</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span>
        <span class="k">return</span> <span class="n">n</span>
    <span class="k">return</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="nf">fib</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span>
</code></pre></div></div> <p>Let’s try that line again:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tmp</span> <span class="o">=</span> <span class="p">[</span><span class="nf">fib</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">16</span><span class="p">)]</span>
</code></pre></div></div> <pre><code class="language-txt">3.34 µs ± 719 ns per loop (mean ± std. dev. of 7 runs, 10 loops each)
</code></pre> <p>Now, let’s check the cache information:</p> <ul> <li>hits: number of times the function was called and the results were already there;</li> <li>misses: number of times the function was called and the results were not there;</li> <li>maxsize: current maximum allowed size of the cache;</li> <li>currsize: actual size of the cache (stored results).</li> </ul> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">print</span><span class="p">(</span><span class="n">fib</span><span class="p">.</span><span class="nf">cache_info</span><span class="p">())</span>
</code></pre></div></div> <pre><code class="language-txt">CacheInfo(hits=1132, misses=16, maxsize=128, currsize=16)
</code></pre> <h3 id="creating-functions-with-defaults-from-partial">Creating functions with defaults from <a href="https://docs.python.org/3/library/functools.html#functools.partial">partial</a></h3> <p>Suppose we have a function, called <code class="language-plaintext highlighter-rouge">divide_by</code>. It is a pretty generic function, but it is usually called with some specific values, like dividing by two, or by three.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">divide_by</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
  <span class="k">return</span> <span class="n">x</span> <span class="o">/</span> <span class="n">y</span>

<span class="nf">print</span><span class="p">(</span><span class="nf">divide_by</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="nf">print</span><span class="p">(</span><span class="nf">divide_by</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="mi">3</span><span class="p">))</span>
</code></pre></div></div> <pre><code class="language-txt">6.0
4.0
</code></pre> <p>What if, instead of creating an entire new function, we could only create different signatures for the function, one for each common y value? That is what <code class="language-plaintext highlighter-rouge">partial</code> is for:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">functools</span> <span class="kn">import</span> <span class="n">partial</span>

<span class="n">divide_by_two</span> <span class="o">=</span> <span class="nf">partial</span><span class="p">(</span><span class="n">divide_by</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="n">divide_by_three</span> <span class="o">=</span> <span class="nf">partial</span><span class="p">(</span><span class="n">divide_by</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>

<span class="nf">print</span><span class="p">(</span><span class="nf">divide_by_two</span><span class="p">(</span><span class="mi">12</span><span class="p">))</span>
<span class="nf">print</span><span class="p">(</span><span class="nf">divide_by_three</span><span class="p">(</span><span class="mi">12</span><span class="p">))</span>
</code></pre></div></div> <pre><code class="language-txt">6.0
4.0
</code></pre>]]></content><author><name></name></author><category term="python"/><category term="programming"/><category term="code"/><category term="improvement"/><category term="python"/><summary type="html"><![CDATA[How to use functions from the default library to improve your code.]]></summary></entry><entry><title type="html">The problem of research code reproducibility</title><link href="https://george-gca.github.io/blog/2022/research-code-reproducibility/" rel="alternate" type="text/html" title="The problem of research code reproducibility"/><published>2022-10-21T15:13:16+00:00</published><updated>2022-10-21T15:13:16+00:00</updated><id>https://george-gca.github.io/blog/2022/research-code-reproducibility</id><content type="html" xml:base="https://george-gca.github.io/blog/2022/research-code-reproducibility/"><![CDATA[<p>Everyone in the research community had that problem already:</p> <blockquote> <p>You found a paper that you want to reproduce. You found out that the original author (or possibly another researcher) published code to run those experiments. You download the code, try to run it, but it doesn’t work. There are missing code, missing datasets, or missing dependencies. Maybe the code is a little outdated, and you need to update it to run it on your machine. Or you need to find out which specific library versions the authors used. You spend hours trying to get the code to run, but to no avail. You try to contact the authors, but they do not respond. You try to fix the code yourself, but it is too complicated. You give up.</p> </blockquote> <p>Who never got so frustrated to the point that you just give up on that code, maybe even on that paper? Hell, I know people that gave up on a whole field of research because they could not reproduce the results of a paper. Multiple times I got caught in this kind of situation, and got me questioning the whole code publishing part. After a lot of afterthought, I came to a partial solution to this problem.</p> <h2 id="the-main-culprit">The main culprit</h2> <p>Most of the time that I am unable to run someone else’s code, it is because of one thing: <strong>dependencies versions are not specified</strong>.</p> <p>Sure, a lot of people create something like <code class="language-plaintext highlighter-rouge">requirements.txt</code>, but they usually lack the version number. Even if they do specify the version number, it is usually not the exact version number. For example, instead of <code class="language-plaintext highlighter-rouge">numpy==1.19.5</code>, they would write <code class="language-plaintext highlighter-rouge">numpy&gt;=1.19.5</code>. This is not good enough. If you want to reproduce someone else’s results, you need to know <strong>exactly</strong> which version of each dependency you need to install. Otherwise, you will get different results. Even if you specify the exact version number, you might still get different results if the authors used a different version of the language, say, Python, or some other low-level dependencies, like cuda or cuDNN.</p> <h2 id="docker-for-the-help">Docker for the help</h2> <p>That is where <a href="https://www.docker.com/">Docker</a> comes in. Docker is a <a href="https://www.docker.com/resources/what-container/">containerization technology</a> that allows you to create an <a href="https://docs.docker.com/glossary/#image">image</a> that packs all the dependencies that you need to run your code. You can then run your code inside a <a href="https://docs.docker.com/glossary/#container">container</a>, and you will <strong>possibly</strong> get the same results as the authors. Making an allusion to object oriented programming, <strong>image</strong> is the class and <strong>container</strong> is an object or an instance from that class. You can even share that image with other people, so they can run your code too. Docker also supports <a href="https://github.com/NVIDIA/nvidia-docker">running code on GPUs</a>.</p> <p>As an example, here is the <a href="https://github.com/george-gca/sr-pytorch-lightning">base code</a> that I used during my master degree. I tried as much as possible to make it reproducible and extensible. That means to not only run the AI model, but also be able to create your own model and run it with the same data and training parameters, to allow comparisons.</p> <p>I decided to split the logic of dealing with Docker (contained in <a href="https://github.com/george-gca/sr-pytorch-lightning/blob/main/Makefile">Makefile</a>) from running the Python code itself (contained in <a href="https://github.com/george-gca/sr-pytorch-lightning/blob/main/start_here.sh">start_here.sh</a>). The recipe for creating the Docker image is inside the <a href="https://github.com/george-gca/sr-pytorch-lightning/blob/main/Dockerfile">Dockerfile</a>, and I also made available a <a href="https://github.com/george-gca/sr-pytorch-lightning/blob/main/Dockerfile_fixed_versions">Dockerfile</a> with all the versions of the dependencies fixed, like you can see in the code snippet below. Everything you might need to run the code is explained in the <a href="https://github.com/george-gca/sr-pytorch-lightning/blob/main/README.md">README</a> file.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="nv">DEBIAN_FRONTEND</span><span class="o">=</span>noninteractive <span class="nv">$APT_INSTALL</span> <span class="se">\</span>
        <span class="nv">bc</span><span class="o">=</span>1.07.1-2 <span class="se">\</span>
        <span class="nv">curl</span><span class="o">=</span>7.58.0-2ubuntu3.18 <span class="se">\</span>
        <span class="nv">git</span><span class="o">=</span>1:2.17.1-1ubuntu0.11 <span class="se">\</span>
        libffi-dev<span class="o">=</span>3.2.1-8 <span class="se">\</span>
        <span class="nv">rsync</span><span class="o">=</span>3.1.2-2.1ubuntu1.4 <span class="se">\</span>
        <span class="nv">wget</span><span class="o">=</span>1.19.4-1ubuntu2.2 <span class="o">&amp;&amp;</span> <span class="se">\</span>

<span class="c"># ==================================================================</span>
<span class="c"># install python libraries via pip</span>
<span class="c"># ------------------------------------------------------------------</span>

    <span class="nv">$PIP_INSTALL</span> <span class="se">\</span>
        <span class="nv">pip</span><span class="o">==</span>22.0.4 <span class="se">\</span>
        <span class="nv">setuptools</span><span class="o">==</span>62.2.0 <span class="se">\</span>
        <span class="nv">wheel</span><span class="o">==</span>0.37.1 <span class="o">&amp;&amp;</span> <span class="se">\</span>
</code></pre></div></div> <p>To ensure reproducibility despite the random number generators, I used the <a href="https://pytorch-lightning.readthedocs.io/en/stable/api/pytorch_lightning.utilities.seed.html#pytorch_lightning.utilities.seed.seed_everything">seed_everything</a> function from PyTorch Lightning. This function sets seed for pseudo-random number generators in: <code class="language-plaintext highlighter-rouge">pytorch</code>, <code class="language-plaintext highlighter-rouge">numpy</code>, <code class="language-plaintext highlighter-rouge">python.random</code>. It also sets the following environment variables: <code class="language-plaintext highlighter-rouge">PL_GLOBAL_SEED</code> and <code class="language-plaintext highlighter-rouge">PL_SEED_WORKERS</code>.</p> <h2 id="docker-doesnt-solve-everything">Docker doesn’t solve everything</h2> <p>As you can probably be thinking, this is not a perfect solution. There are still problems that might surge, and that you need to be aware of, since some of these are from out of our control.</p> <h3 id="repositories-changes">Repositories changes</h3> <p>Look, for example, this part of the <a href="https://github.com/george-gca/sr-pytorch-lightning/blob/main/Dockerfile_fixed_versions">Dockerfile</a>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># temporary solution for bug</span>
<span class="c"># see https://forums.developer.nvidia.com/t/gpg-error-http-developer-download-nvidia-com-compute-cuda-repos-ubuntu1804-x86-64/212904/3</span>
apt-key adv <span class="nt">--fetch-keys</span> https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/3bf863cc.pub <span class="o">&amp;&amp;</span> <span class="se">\</span>
apt-key adv <span class="nt">--fetch-keys</span> https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/3bf863cc.pub <span class="o">&amp;&amp;</span> <span class="se">\</span>
</code></pre></div></div> <p>This is a solution for a bug that I found with the NVIDIA repository. Basically, they are (were?) in the process of rotating their repository GPG public keys, which is used to sign the packages. This was causing an error in the <code class="language-plaintext highlighter-rouge">apt-get update</code> command when creating the Docker image, and this was not happening during the entirety of my experiments, but happened by the time I decided to publish this code.</p> <h3 id="dependencies-dependencies">Dependencies’ dependencies</h3> <p>Sometimes some of your dependencies specific version requires specific versions of its own dependencies. This happened to me when specifying <code class="language-plaintext highlighter-rouge">tensorboard==2.9.0</code>, which caused an error when building the Docker image. To fix this, I needed to define the proper <code class="language-plaintext highlighter-rouge">protobuf</code> version to install, even though my code does not use <code class="language-plaintext highlighter-rouge">protobuf</code> directly.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">prettytable</span><span class="o">==</span>3.3.0 <span class="se">\</span>
<span class="c"># specify protobuf to avoid bug with tensorboard</span>
<span class="c"># https://developers.google.com/protocol-buffers/docs/news/2022-05-06#python-updates</span>
<span class="nv">protobuf</span><span class="o">==</span>3.20 <span class="se">\</span>
pytorch-lightning<span class="o">==</span>1.6.3 <span class="se">\</span>
<span class="nv">tensorboard</span><span class="o">==</span>2.9.0 <span class="se">\</span>
</code></pre></div></div>]]></content><author><name></name></author><category term="research-code"/><category term="research"/><category term="programming"/><category term="reproducibility"/><category term="code"/><summary type="html"><![CDATA[A brief overview of the problem of research code reproducibility.]]></summary></entry><entry><title type="html">Creating localized blog posts</title><link href="https://george-gca.github.io/blog/2022/localized-blog/" rel="alternate" type="text/html" title="Creating localized blog posts"/><published>2022-09-30T17:40:13+00:00</published><updated>2022-09-30T17:40:13+00:00</updated><id>https://george-gca.github.io/blog/2022/localized-blog</id><content type="html" xml:base="https://george-gca.github.io/blog/2022/localized-blog/"><![CDATA[<p>This post is part of a series of posts that explain how to set up your own site based on the al-folio theme and add support for a second language:</p> <ul> <li><a href="/blog/2022/running-local-al-folio/">Running locally your own al-folio website</a></li> <li><a href="/blog/2022/dual-language-al-folio/">Turning your al-folio into a dual-language website</a></li> <li><a href="/blog/2022/localized-cv/">Creating localized CV pages</a></li> <li><a href="/blog/2022/localized-projects/">Creating localized Projects pages</a></li> <li>Creating localized blog posts</li> </ul> <hr/> <p>We <a href="/blog/2022/running-local-al-folio/">created a local al-folio website</a>, <a href="/blog/2022/dual-language-al-folio/">added support for another language in it</a>, <a href="/blog/2022/localized-cv/">created localized CV pages</a>, and <a href="/blog/2022/localized-projects/">project pages</a>. Now, let’s localize the blog part.</p> <h2 id="creating-the-structure">Creating the structure</h2> <p>If you go to the blog section of your al-folio site, you’ll realize that it is quite empty, although there are posts in the template. Actually, the <a href="https://github.com/kurtsson/jekyll-multiple-languages-plugin">Jekyll Multiple Languages Plugin</a> already support <a href="https://github.com/kurtsson/jekyll-multiple-languages-plugin#57-creating-posts">localized blog posts</a>. It is not displaying them because it is not finding them. So, let’s create the correct structure for them. Create a <code class="language-plaintext highlighter-rouge">_posts/</code> directory inside each language under the <code class="language-plaintext highlighter-rouge">_i18n/</code> directory, and copy the content of the <code class="language-plaintext highlighter-rouge">_posts/</code> directory from the root of the website to the language directories. So, for example, if you have a <code class="language-plaintext highlighter-rouge">_posts/</code> directory with the following content:</p> <ul> <li>_posts/2015-03-15-formatting-and-links.md</li> <li>_posts/2015-05-15-images.md</li> <li>_posts/2015-07-15-code.md</li> <li>_posts/2015-10-20-comments.md</li> <li>_posts/2015-10-20-math.md</li> <li>_posts/2018-12-22-distill.md</li> <li>_posts/2020-09-28-github-metadata.md</li> <li>_posts/2020-09-28-twitter.md</li> <li>_posts/2021-07-04-diagrams.md</li> <li>_posts/2022-02-01-redirect.md</li> </ul> <p>You should create the following structure for all your languages, in this example, the English language:</p> <ul> <li>_i18n/en/_posts/2015-03-15-formatting-and-links.md</li> <li>_i18n/en/_posts/2015-05-15-images.md</li> <li>_i18n/en/_posts/2015-07-15-code.md</li> <li>_i18n/en/_posts/2015-10-20-comments.md</li> <li>_i18n/en/_posts/2015-10-20-math.md</li> <li>_i18n/en/_posts/2018-12-22-distill.md</li> <li>_i18n/en/_posts/2020-09-28-github-metadata.md</li> <li>_i18n/en/_posts/2020-09-28-twitter.md</li> <li>_i18n/en/_posts/2021-07-04-diagrams.md</li> <li>_i18n/en/_posts/2022-02-01-redirect.md</li> </ul> <p>Create that, translate the pages contents, and it will now show the missing blog posts. Easy, right? Errr, you are missing a few small details: the date format, the reading time, and the link when clicking on a tag in the header of the blog section. The bad news is that Jekyll doesn’t natively support localized date formats. The good news is that it is not that hard to create it though. Let’s start with the date format.</p> <h2 id="localizing-the-date-format">Localizing the date format</h2> <p>There are two main formats of date used in the template: in the posts list and inside the posts, with the format <code class="language-plaintext highlighter-rouge">September 28, 2020</code>, and when filtering the posts (e.g.: by tag), with the format <code class="language-plaintext highlighter-rouge">Sep 28, 2020</code>. The easiest way I found of localizing them is by first manually translating the months names. For this, add the following section to your language files (<code class="language-plaintext highlighter-rouge">_i18n/en.yml</code> and <code class="language-plaintext highlighter-rouge">_i18n/pt-br.yml</code>), translating the months names to your language:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">months</span><span class="pi">:</span>
  <span class="na">long</span><span class="pi">:</span>
    <span class="na">january</span><span class="pi">:</span> <span class="s">January</span>
    <span class="na">february</span><span class="pi">:</span> <span class="s">February</span>
    <span class="na">march</span><span class="pi">:</span> <span class="s">March</span>
    <span class="na">april</span><span class="pi">:</span> <span class="s">April</span>
    <span class="na">may</span><span class="pi">:</span> <span class="s">May</span>
    <span class="na">june</span><span class="pi">:</span> <span class="s">June</span>
    <span class="na">july</span><span class="pi">:</span> <span class="s">July</span>
    <span class="na">august</span><span class="pi">:</span> <span class="s">August</span>
    <span class="na">september</span><span class="pi">:</span> <span class="s">September</span>
    <span class="na">october</span><span class="pi">:</span> <span class="s">October</span>
    <span class="na">november</span><span class="pi">:</span> <span class="s">November</span>
    <span class="na">december</span><span class="pi">:</span> <span class="s">December</span>
  <span class="na">short</span><span class="pi">:</span>
    <span class="na">january</span><span class="pi">:</span> <span class="s">Jan</span>
    <span class="na">february</span><span class="pi">:</span> <span class="s">Feb</span>
    <span class="na">march</span><span class="pi">:</span> <span class="s">Mar</span>
    <span class="na">april</span><span class="pi">:</span> <span class="s">Apr</span>
    <span class="na">may</span><span class="pi">:</span> <span class="s">May</span>
    <span class="na">june</span><span class="pi">:</span> <span class="s">Jun</span>
    <span class="na">july</span><span class="pi">:</span> <span class="s">Jul</span>
    <span class="na">august</span><span class="pi">:</span> <span class="s">Aug</span>
    <span class="na">september</span><span class="pi">:</span> <span class="s">Sep</span>
    <span class="na">october</span><span class="pi">:</span> <span class="s">Oct</span>
    <span class="na">november</span><span class="pi">:</span> <span class="s">Nov</span>
    <span class="na">december</span><span class="pi">:</span> <span class="s">Dec</span>
</code></pre></div></div> <p>Since the dates are used in a variety of locations, let’s create a function to reuse the code. Create the file <code class="language-plaintext highlighter-rouge">_includes/date_format.html</code> with the following code:</p> <div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">months</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'january|february|march|april|may|june|july|august|september|october|november|december'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">split</span><span class="p">:</span><span class="w"> </span><span class="s1">'|'</span><span class="w"> </span><span class="cp">%}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">m</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">include</span><span class="p">.</span><span class="nv">date_from</span><span class="p">.</span><span class="nv">date</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">date</span><span class="p">:</span><span class="w"> </span><span class="s1">'%-m'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">minus</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="cp">%}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">day</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">include</span><span class="p">.</span><span class="nv">date_from</span><span class="p">.</span><span class="nv">date</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">date</span><span class="p">:</span><span class="w"> </span><span class="s1">'%d'</span><span class="w"> </span><span class="cp">%}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">capture</span><span class="w"> </span><span class="nv">month</span><span class="w"> </span><span class="cp">%}</span>months.<span class="cp">{{</span><span class="w"> </span><span class="nv">include</span><span class="p">.</span><span class="nv">format</span><span class="w"> </span><span class="cp">}}</span>.<span class="cp">{{</span><span class="w"> </span><span class="nv">months</span><span class="p">[</span><span class="nv">m</span><span class="p">]</span><span class="w"> </span><span class="cp">}}{%</span><span class="w"> </span><span class="nt">endcapture</span><span class="w"> </span><span class="cp">%}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">assign</span><span class="w"> </span><span class="nv">year</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">include</span><span class="p">.</span><span class="nv">date_from</span><span class="p">.</span><span class="nv">date</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">date</span><span class="p">:</span><span class="w"> </span><span class="s1">'%Y'</span><span class="w"> </span><span class="cp">%}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">if</span><span class="w"> </span><span class="nv">site</span><span class="p">.</span><span class="nv">lang</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s1">'en'</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{%-</span><span class="w"> </span><span class="nt">t</span><span class="w"> </span><span class="nv">month</span><span class="w"> </span><span class="cp">%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">day</span><span class="w"> </span><span class="cp">}}</span>, <span class="cp">{{</span><span class="w"> </span><span class="nv">year</span><span class="w"> </span><span class="cp">-}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">else</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{{-</span><span class="w"> </span><span class="nv">day</span><span class="w"> </span><span class="cp">}}</span> de <span class="cp">{%</span><span class="w"> </span><span class="nt">t</span><span class="w"> </span><span class="nv">month</span><span class="w"> </span><span class="cp">%}</span>, <span class="cp">{{</span><span class="w"> </span><span class="nv">year</span><span class="w"> </span><span class="cp">-}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">endif</span><span class="w"> </span><span class="cp">%}</span>
</code></pre></div></div> <p>This code defines a function that extracts the month, day, and year from the <code class="language-plaintext highlighter-rouge">date_from</code> variable, formats according to <code class="language-plaintext highlighter-rouge">format</code>, and returns the formatted localized string. Notice that, to access the given variables, we must refer to them preceded with <code class="language-plaintext highlighter-rouge">include.</code>. The <code class="language-plaintext highlighter-rouge">format</code> variable can be either <code class="language-plaintext highlighter-rouge">long</code> or <code class="language-plaintext highlighter-rouge">short</code>, as we defined above, and the <code class="language-plaintext highlighter-rouge">date_from</code> variable must have a date object inside it. The function also considers the current language. Now, let’s call the function with the proper parameters. Inside the file <code class="language-plaintext highlighter-rouge">blog/index.html</code>, do the following changes:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- {{ post.date | date: '%B %-d, %Y' }} --&gt;</span>
{% include date_format.html format="long" date_from=post %}
</code></pre></div></div> <p>The posts list will now display the date format correctly. Just do the same changes for every other place where the date format appears, like the filters pages, changing the month format to <code class="language-plaintext highlighter-rouge">"short"</code> when needed, and also giving the correct <code class="language-plaintext highlighter-rouge">date_from</code> parameter. For example, for the file <code class="language-plaintext highlighter-rouge">_layouts/archive-category.html</code> the change will be:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;th scope="row"&gt;{{ post.date | date: "%b %-d, %Y" }}&lt;/th&gt; --&gt;</span>
<span class="nt">&lt;th</span> <span class="na">scope=</span><span class="s">"row"</span><span class="nt">&gt;</span>{% include date_format.html format="short" date_from=post %}<span class="nt">&lt;/th&gt;</span>
</code></pre></div></div> <h2 id="localizing-the-reading-time">Localizing the reading time</h2> <p>Now, let’s localize the reading time. Do the following changes to the file <code class="language-plaintext highlighter-rouge">blog/index.html</code>:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- {{ read_time }} min read &amp;nbsp; &amp;middot; &amp;nbsp; --&gt;</span>
{% if site.lang == 'en' %}{{ read_time }} min read{% else %}Leitura de {{ read_time }} min{% endif %} <span class="ni">&amp;nbsp;</span> <span class="ni">&amp;middot;</span> <span class="ni">&amp;nbsp;</span>
</code></pre></div></div> <h2 id="fixing-blog-archive-navigation">Fixing blog archive navigation</h2> <p>When you click to filter blog posts by tag, year, or category, the page will show the posts, but the navigation will be broken. This is because these navigations are not localized. To fix this, modify the following lines in files <code class="language-plaintext highlighter-rouge">_layouts/archive-category.html</code>, <code class="language-plaintext highlighter-rouge">_layouts/archive-tag.html</code>, and <code class="language-plaintext highlighter-rouge">_layouts/archive-year.html</code>:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;a class="post-link" href="{{ post.url | relative_url }}"&gt;{{ post.title }}&lt;/a&gt; --&gt;</span>
<span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"post-link"</span> <span class="na">href=</span><span class="s">"{{ post.url | prepend: site.baseurl }}"</span><span class="nt">&gt;</span>{{ post.title }}<span class="nt">&lt;/a&gt;</span>
</code></pre></div></div> <p>Also, change the following line in the file <code class="language-plaintext highlighter-rouge">blog/index.html</code>:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;i class="fas fa-hashtag fa-sm"&gt;&lt;/i&gt; &lt;a href="{{ tag | prepend: '/blog/tag/' | relative_url }}"&gt;{{ tag }}&lt;/a&gt; --&gt;</span>
<span class="nt">&lt;i</span> <span class="na">class=</span><span class="s">"fas fa-hashtag fa-sm"</span><span class="nt">&gt;&lt;/i&gt;</span> <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"{{ tag | prepend: '/blog/tag/' | prepend: site.baseurl }}"</span><span class="nt">&gt;</span>{{ tag }}<span class="nt">&lt;/a&gt;</span>
</code></pre></div></div> <h2 id="fixing-pagination">Fixing pagination</h2> <p>If your blog has enough posts to enable more pages with results (pagination), you’ll realize that it is not yet translated. To fix this, first we need to create localized words for <code class="language-plaintext highlighter-rouge">Older</code> and <code class="language-plaintext highlighter-rouge">Newer</code> in the language files <code class="language-plaintext highlighter-rouge">_i18n/en.yml</code> and <code class="language-plaintext highlighter-rouge">_i18n/pt-br.yml</code>, respectivelly:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">pagination</span><span class="pi">:</span>
  <span class="na">newer</span><span class="pi">:</span> <span class="s">Newer</span>
  <span class="na">older</span><span class="pi">:</span> <span class="s">Older</span>
</code></pre></div></div> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">pagination</span><span class="pi">:</span>
  <span class="na">newer</span><span class="pi">:</span> <span class="s">Recentes</span>
  <span class="na">older</span><span class="pi">:</span> <span class="s">Antigas</span>
</code></pre></div></div> <p>Next, we change all uses of <code class="language-plaintext highlighter-rouge">relative_url</code> for <code class="language-plaintext highlighter-rouge">prepend: site.baseurl</code> in the file <code class="language-plaintext highlighter-rouge">_includes/pagination.html</code>, so it correctly handles the language urls. Also, change the words “Newer” and “Older” for its correspondent translation from the correct language file:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{%- if paginator.total_pages &gt; 1 -%}
<span class="nt">&lt;nav</span> <span class="na">aria-label=</span><span class="s">"Blog page naviation"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"pagination pagination-lg justify-content-center"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"page-item {% unless paginator.previous_page %}disabled{% endunless %}"</span><span class="nt">&gt;</span>
      <span class="c">&lt;!-- &lt;a class="page-link" href="{{ paginator.previous_page_path | relative_url }}" tabindex="-1" aria-disabled="{{ paginator.previous_page }}"&gt;Newer&lt;/a&gt; --&gt;</span>
      <span class="nt">&lt;a</span>
        <span class="na">class=</span><span class="s">"page-link"</span>
        <span class="na">href=</span><span class="s">"{{ paginator.previous_page_path |  prepend: site.baseurl }}"</span>
        <span class="na">tabindex=</span><span class="s">"-1"</span>
        <span class="na">aria-disabled=</span><span class="s">"{{ paginator.previous_page }}"</span>
        <span class="nt">&gt;</span>{% t pagination.newer %}<span class="nt">&lt;/a</span>
      <span class="nt">&gt;</span>
    <span class="nt">&lt;/li&gt;</span>
    {%- if paginator.page_trail -%} {% for trail in paginator.page_trail -%}
    <span class="c">&lt;!-- &lt;li class="page-item {% if page.url == trail.path %}active{% endif %}"&gt;&lt;a class="page-link" href="{{ trail.path | relative_url }}" title="{{trail.title}}"&gt;{{ trail.num }}&lt;/a&gt;&lt;/li&gt; --&gt;</span>
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"page-item {% if page.url == trail.path %}active{% endif %}"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"page-link"</span> <span class="na">href=</span><span class="s">"{{ trail.path | prepend: site.baseurl }}"</span> <span class="na">title=</span><span class="s">"{{trail.title}}"</span><span class="nt">&gt;</span>{{ trail.num }}<span class="nt">&lt;/a&gt;</span>
    <span class="nt">&lt;/li&gt;</span>
    {% endfor -%} {%- endif -%}
    <span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"page-item {% unless paginator.next_page %}disabled{% endunless %}"</span><span class="nt">&gt;</span>
      <span class="c">&lt;!-- &lt;a class="page-link" href="{{ paginator.next_page_path | relative_url }}"&gt;Older&lt;/a&gt; --&gt;</span>
      <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"page-link"</span> <span class="na">href=</span><span class="s">"{{ paginator.next_page_path | prepend: site.baseurl }}"</span><span class="nt">&gt;</span>{% t pagination.older %}<span class="nt">&lt;/a&gt;</span>
    <span class="nt">&lt;/li&gt;</span>
  <span class="nt">&lt;/ul&gt;</span>
<span class="nt">&lt;/nav&gt;</span>
{%- endif -%}
</code></pre></div></div> <h2 id="fixing-page-title-in-the-browser">Fixing page title in the browser</h2> <p>If you filter your blog posts by year, you’ll notice that the year is not displayed in the browser title. To fix this, modify the following lines in the file <code class="language-plaintext highlighter-rouge">_includes/metadata.html</code>:</p> <div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">if</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s1">'/blog/index.html'</span><span class="w"> </span><span class="cp">%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">site</span><span class="p">.</span><span class="nv">blog_nav_title</span><span class="w"> </span><span class="cp">}}</span> | <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">elsif</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="ow">contains</span><span class="w"> </span><span class="s1">'/blog/'</span><span class="w"> </span><span class="cp">%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span> | <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">elsif</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="ow">contains</span><span class="w"> </span><span class="s1">'Announcement'</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">elsif</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s1">'blank'</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s1">'/'</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{%</span><span class="w"> </span><span class="nt">t</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="cp">%}</span> | <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">else</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">endif</span><span class="w"> </span><span class="cp">-%}</span>
</code></pre></div></div> <p>for these:</p> <div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">if</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s1">'/blog/index.html'</span><span class="w"> </span><span class="cp">%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">site</span><span class="p">.</span><span class="nv">blog_nav_title</span><span class="w"> </span><span class="cp">}}</span> | <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">elsif</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="ow">contains</span><span class="w"> </span><span class="s1">'/blog/'</span><span class="w"> </span><span class="cp">%}</span>
  <span class="cp">{%-</span><span class="w"> </span><span class="nt">capture</span><span class="w"> </span><span class="nv">blog_year</span><span class="w"> </span><span class="cp">-%}{{</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">slice</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">11</span><span class="w"> </span><span class="cp">}}{%-</span><span class="w"> </span><span class="nt">endcapture</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{%-</span><span class="w"> </span><span class="nt">if</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="nv">blog_year</span><span class="w"> </span><span class="cp">-%}</span>
    <span class="cp">{{</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">date</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="nf">date</span><span class="p">:</span><span class="w"> </span><span class="s1">'%Y'</span><span class="w"> </span><span class="cp">}}</span> | <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
  <span class="cp">{%-</span><span class="w"> </span><span class="nt">else</span><span class="w"> </span><span class="cp">-%}</span>
    <span class="cp">{{</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span> | <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
  <span class="cp">{%-</span><span class="w"> </span><span class="nt">endif</span><span class="w"> </span><span class="cp">-%}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">elsif</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s1">'blank'</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s1">'/'</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{%-</span><span class="w"> </span><span class="nt">if</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="ow">contains</span><span class="w"> </span><span class="s1">'Announcement'</span><span class="w"> </span><span class="cp">-%}</span>
    <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
  <span class="cp">{%-</span><span class="w"> </span><span class="nt">else</span><span class="w"> </span><span class="cp">-%}</span>
    <span class="cp">{%</span><span class="w"> </span><span class="nt">t</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="cp">%}</span> | <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
  <span class="cp">{%-</span><span class="w"> </span><span class="nt">endif</span><span class="w"> </span><span class="cp">-%}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">else</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">endif</span><span class="w"> </span><span class="cp">-%}</span>
</code></pre></div></div>]]></content><author><name></name></author><category term="website"/><category term="development"/><category term="al-folio"/><category term="website"/><category term="jekyll"/><category term="localization"/><category term="languages"/><summary type="html"><![CDATA[How to create localized blog on your al-folio website.]]></summary></entry><entry><title type="html">Creating localized Projects pages</title><link href="https://george-gca.github.io/blog/2022/localized-projects/" rel="alternate" type="text/html" title="Creating localized Projects pages"/><published>2022-09-30T11:57:13+00:00</published><updated>2022-09-30T11:57:13+00:00</updated><id>https://george-gca.github.io/blog/2022/localized-projects</id><content type="html" xml:base="https://george-gca.github.io/blog/2022/localized-projects/"><![CDATA[<p>This post is part of a series of posts that explain how to set up your own site based on the al-folio theme and add support for a second language:</p> <ul> <li><a href="/blog/2022/running-local-al-folio/">Running locally your own al-folio website</a></li> <li><a href="/blog/2022/dual-language-al-folio/">Turning your al-folio into a dual-language website</a></li> <li><a href="/blog/2022/localized-cv/">Creating localized CV pages</a></li> <li>Creating localized Projects pages</li> <li><a href="/blog/2022/localized-blog/">Creating localized blog posts</a></li> </ul> <hr/> <p>We <a href="/blog/2022/running-local-al-folio/">created a local al-folio website</a>, <a href="/blog/2022/dual-language-al-folio/">added support for another language in it</a>, and <a href="/blog/2022/localized-cv/">created localized CV pages</a>. Now, let’s localize the Projects page.</p> <h2 id="localizing-pages-descriptions">Localizing pages descriptions</h2> <p>Let’s first localize all the pages descriptions. This will start with us creating the keys in the <code class="language-plaintext highlighter-rouge">_i18n/en.yml</code> and <code class="language-plaintext highlighter-rouge">_i18n/pt-br.yml</code> files, and moving there the referred content from the pages. So, let’s start by creating the descriptions both in the file root and inside the <code class="language-plaintext highlighter-rouge">projects</code> key. The new <code class="language-plaintext highlighter-rouge">_i18n/en.yml</code> content will be:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">titles</span><span class="pi">:</span>
  <span class="na">about</span><span class="pi">:</span> <span class="s">about</span>
  <span class="na">blog</span><span class="pi">:</span> <span class="s">blog</span>
  <span class="na">cv</span><span class="pi">:</span> <span class="s">cv</span>
  <span class="na">news</span><span class="pi">:</span> <span class="s">news</span>
  <span class="na">projects</span><span class="pi">:</span> <span class="s">projects</span>
  <span class="na">publications</span><span class="pi">:</span> <span class="s">publications</span>
  <span class="na">repositories</span><span class="pi">:</span> <span class="s">repositories</span>
  <span class="na">teaching</span><span class="pi">:</span> <span class="s">teaching</span>
  <span class="na">submenus</span><span class="pi">:</span> <span class="s">submenus</span>
  <span class="na">unk</span><span class="pi">:</span> <span class="s">page not found</span>
<span class="na">descriptions</span><span class="pi">:</span>
  <span class="na">about</span><span class="pi">:</span> <span class="s">about me</span>
  <span class="na">blog</span><span class="pi">:</span> <span class="s">blogging</span>
  <span class="na">publications</span><span class="pi">:</span> <span class="s">publications by categories in reversed chronological order. generated by jekyll-scholar.</span>
  <span class="na">projects</span><span class="pi">:</span> <span class="s">A growing collection of your cool projects.</span>
  <span class="na">repositories</span><span class="pi">:</span> <span class="s">Edit the `_data/repositories.yml` and change the `github_users` and `github_repos` lists to include your own GitHub profile and repositories.</span>
  <span class="na">teaching</span><span class="pi">:</span> <span class="s">Materials for courses you taught. Replace this text with your description.</span>
  <span class="na">unk</span><span class="pi">:</span> <span class="s">Looks like there has been a mistake. Nothing exists here.</span>
<span class="na">projects</span><span class="pi">:</span>
  <span class="na">titles</span><span class="pi">:</span>
    <span class="na">project1</span><span class="pi">:</span> <span class="s">Project </span><span class="m">1</span>
    <span class="na">project2</span><span class="pi">:</span> <span class="s">Project </span><span class="m">2</span>
    <span class="na">project3</span><span class="pi">:</span> <span class="s">Project </span><span class="m">3</span>
    <span class="na">project4</span><span class="pi">:</span> <span class="s">Project </span><span class="m">4</span>
    <span class="na">project5</span><span class="pi">:</span> <span class="s">Project </span><span class="m">5</span>
    <span class="na">project6</span><span class="pi">:</span> <span class="s">Project </span><span class="m">6</span>
  <span class="na">descriptions</span><span class="pi">:</span>
    <span class="na">project1</span><span class="pi">:</span> <span class="s">a project with a background image</span>
    <span class="na">project2</span><span class="pi">:</span> <span class="s">a project with a background image</span>
    <span class="na">project3</span><span class="pi">:</span> <span class="s">a project that redirects to another website</span>
    <span class="na">project4</span><span class="pi">:</span> <span class="s">another without an image</span>
    <span class="na">project5</span><span class="pi">:</span> <span class="s">a project with a background image</span>
    <span class="na">project6</span><span class="pi">:</span> <span class="s">a project with no image</span>
</code></pre></div></div> <p>And now for the <code class="language-plaintext highlighter-rouge">_i18n/pt-br.yml</code>:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">titles</span><span class="pi">:</span>
  <span class="na">about</span><span class="pi">:</span> <span class="s">sobre</span>
  <span class="na">blog</span><span class="pi">:</span> <span class="s">blog</span>
  <span class="na">cv</span><span class="pi">:</span> <span class="s">cv</span>
  <span class="na">news</span><span class="pi">:</span> <span class="s">novidades</span>
  <span class="na">projects</span><span class="pi">:</span> <span class="s">projetos</span>
  <span class="na">publications</span><span class="pi">:</span> <span class="s">publicações</span>
  <span class="na">repositories</span><span class="pi">:</span> <span class="s">repositórios</span>
  <span class="na">teaching</span><span class="pi">:</span> <span class="s">ensino</span>
  <span class="na">submenus</span><span class="pi">:</span> <span class="s">submenus</span>
  <span class="na">unk</span><span class="pi">:</span> <span class="s">página não encontrada</span>
<span class="na">descriptions</span><span class="pi">:</span>
  <span class="na">about</span><span class="pi">:</span> <span class="s">sobre</span>
  <span class="na">blog</span><span class="pi">:</span> <span class="s">blogging</span>
  <span class="na">publications</span><span class="pi">:</span> <span class="s">publicações por categoria em ordem cronológica reversa. gerado pelo jekyll-scholar.</span>
  <span class="na">projects</span><span class="pi">:</span> <span class="s">Uma crescente coleção de seus projetos interessantes.</span>
  <span class="na">repositories</span><span class="pi">:</span> <span class="s">Edite o `_data/repositories.yml` e mude as listas `github_users` e `github_repos` para incluir seu próprio perfil do GitHub e repositórios.</span>
  <span class="na">teaching</span><span class="pi">:</span> <span class="s">Materiais de cursos que você ministrou. Substitua esse texto com sua descrição.</span>
  <span class="na">unk</span><span class="pi">:</span> <span class="s">Parece que ocorreu um erro. Não existe nada aqui.</span>
<span class="na">projects</span><span class="pi">:</span>
  <span class="na">titles</span><span class="pi">:</span>
    <span class="na">project1</span><span class="pi">:</span> <span class="s">Projeto </span><span class="m">1</span>
    <span class="na">project2</span><span class="pi">:</span> <span class="s">Projeto </span><span class="m">2</span>
    <span class="na">project3</span><span class="pi">:</span> <span class="s">Projeto </span><span class="m">3</span>
    <span class="na">project4</span><span class="pi">:</span> <span class="s">Projeto </span><span class="m">4</span>
    <span class="na">project5</span><span class="pi">:</span> <span class="s">Projeto </span><span class="m">5</span>
    <span class="na">project6</span><span class="pi">:</span> <span class="s">Projeto </span><span class="m">6</span>
  <span class="na">descriptions</span><span class="pi">:</span>
    <span class="na">project1</span><span class="pi">:</span> <span class="s">um projeto com imagem de fundo</span>
    <span class="na">project2</span><span class="pi">:</span> <span class="s">um projeto com imagem de fundo</span>
    <span class="na">project3</span><span class="pi">:</span> <span class="s">um projeto que redireciona pra outro website</span>
    <span class="na">project4</span><span class="pi">:</span> <span class="s">outro sem imagem</span>
    <span class="na">project5</span><span class="pi">:</span> <span class="s">um projeto com imagem de fundo</span>
    <span class="na">project6</span><span class="pi">:</span> <span class="s">um projeto sem imagem</span>
</code></pre></div></div> <p>Next, update all the pages to use the new keys. Those will be: <code class="language-plaintext highlighter-rouge">404.html</code>, <code class="language-plaintext highlighter-rouge">_pages/projects.md</code>, <code class="language-plaintext highlighter-rouge">_pages/publications.md</code>, <code class="language-plaintext highlighter-rouge">_pages/repositories.md</code>, <code class="language-plaintext highlighter-rouge">_pages/teaching.md</code>, and all projects inside <code class="language-plaintext highlighter-rouge">_projects/</code> directory. For example, the new description in <code class="language-plaintext highlighter-rouge">404.html</code> will be:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>description: descriptions.unk
</code></pre></div></div> <p>and in <code class="language-plaintext highlighter-rouge">_projects/1_project.md</code>:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>description: projects.descriptions.project1
</code></pre></div></div> <p>Also, update <code class="language-plaintext highlighter-rouge">_layouts/cv.html</code> and <code class="language-plaintext highlighter-rouge">_layouts/page.html</code> to only display the translation description if a description is defined in the markdown file. The new <code class="language-plaintext highlighter-rouge">_layouts/page.html</code> will have:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;p class="post-description"&gt;{{ page.description }}&lt;/p&gt; --&gt;</span>
<span class="nt">&lt;p</span> <span class="na">class=</span><span class="s">"post-description"</span><span class="nt">&gt;</span>{% if page.description %}{% t page.description %}{% endif %}<span class="nt">&lt;/p&gt;</span>
</code></pre></div></div> <p>Now the descriptions should also be localized. The titles and the descriptions of the projects when a project is opened should also be localized, but not in the projects overview page. So, let’s fix this.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/blog/2022-09-30-localized-projects/not_localized_projects_overview-480.webp 480w,/assets/img/blog/2022-09-30-localized-projects/not_localized_projects_overview-800.webp 800w,/assets/img/blog/2022-09-30-localized-projects/not_localized_projects_overview-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/blog/2022-09-30-localized-projects/not_localized_projects_overview.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <div class="caption"> Projects overview still not working. </div> <h2 id="localizing-projects-overview">Localizing projects overview</h2> <p>When you look inside <code class="language-plaintext highlighter-rouge">_pages/projects.md</code>, you will see more code than in your regular markdown file. The authors decided to call here the html code for building the main layout of the overview page. The interesting parts are these ones:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{% if page.horizontal -%}
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"row row-cols-2"</span><span class="nt">&gt;</span>{%- for project in sorted_projects -%} {% include projects_horizontal.html %} {%- endfor %}<span class="nt">&lt;/div&gt;</span>
<span class="nt">&lt;/div&gt;</span>
{%- else -%}
<span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"grid"</span><span class="nt">&gt;</span>{%- for project in sorted_projects -%} {% include projects.html %} {%- endfor %}<span class="nt">&lt;/div&gt;</span>
{%- endif -%}
</code></pre></div></div> <p>These parts mean that there is a horizontal and a vertical layout for the projects overview page. The horizontal layout is used when the <code class="language-plaintext highlighter-rouge">horizontal</code> key is set to <code class="language-plaintext highlighter-rouge">true</code> in the header of this page, and the vertical otherwise. These layouts can both be found in <code class="language-plaintext highlighter-rouge">_includes/projects_horizontal.html</code> and <code class="language-plaintext highlighter-rouge">_includes/projects.html</code>, respectively. These are the files that we need to update to localize the projects overview page. The changes will basically be the same on both files: we need to add the <code class="language-plaintext highlighter-rouge">t</code> tag to the titles and descriptions of the projects, and also correctly update the links to them. The changes to the <code class="language-plaintext highlighter-rouge">_includes/projects_horizontal.html</code> will be:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;a href="{{ project.url | relative_url }}"&gt; --&gt;</span>
<span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"{{ project.url | prepend: site.baseurl }}"</span><span class="nt">&gt;</span>
  <span class="c">&lt;!-- &lt;h3 class="card-title text-lowercase"&gt;{{ project.title }}&lt;/h3&gt;
&lt;p class="card-text"&gt;{{ project.description }}&lt;/p&gt; --&gt;</span>

  <span class="nt">&lt;h3</span> <span class="na">class=</span><span class="s">"card-title text-lowercase"</span><span class="nt">&gt;</span>{% t project.title %}<span class="nt">&lt;/h3&gt;</span>
  <span class="nt">&lt;p</span> <span class="na">class=</span><span class="s">"card-text"</span><span class="nt">&gt;</span>{% t project.description %}<span class="nt">&lt;/p&gt;&lt;/a</span>
<span class="nt">&gt;</span>
</code></pre></div></div> <p>Now, the projects overview is displayed correctly. But, if you look closely, you’ll notice that the projects categories have not been translated. Let’s fix this.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/blog/2022-09-30-localized-projects/localized_projects_overview-480.webp 480w,/assets/img/blog/2022-09-30-localized-projects/localized_projects_overview-800.webp 800w,/assets/img/blog/2022-09-30-localized-projects/localized_projects_overview-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/blog/2022-09-30-localized-projects/localized_projects_overview.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <div class="caption"> Projects overview now working. </div> <h2 id="localizing-projects-categories">Localizing projects categories</h2> <p>The categories will only be translated when displaying, not inside the projects’ headers. This means that, when creating a project, you will still use the categories in English, like in <code class="language-plaintext highlighter-rouge">_projects/1_project.md</code>:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">category</span><span class="pi">:</span> <span class="s">work</span>
</code></pre></div></div> <p>For this, create the localized version of the categories for both languages. Let’s keep this inside the <code class="language-plaintext highlighter-rouge">projects</code> key, so that it will now look like this in <code class="language-plaintext highlighter-rouge">_i18n/en.yml</code>:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">projects</span><span class="pi">:</span>
  <span class="na">titles</span><span class="pi">:</span>
    <span class="na">project1</span><span class="pi">:</span> <span class="s">Project </span><span class="m">1</span>
    <span class="na">project2</span><span class="pi">:</span> <span class="s">Project </span><span class="m">2</span>
    <span class="na">project3</span><span class="pi">:</span> <span class="s">Project </span><span class="m">3</span>
    <span class="na">project4</span><span class="pi">:</span> <span class="s">Project </span><span class="m">4</span>
    <span class="na">project5</span><span class="pi">:</span> <span class="s">Project </span><span class="m">5</span>
    <span class="na">project6</span><span class="pi">:</span> <span class="s">Project </span><span class="m">6</span>
  <span class="na">descriptions</span><span class="pi">:</span>
    <span class="na">project1</span><span class="pi">:</span> <span class="s">a project with a background image</span>
    <span class="na">project2</span><span class="pi">:</span> <span class="s">a project with a background image</span>
    <span class="na">project3</span><span class="pi">:</span> <span class="s">a project that redirects to another website</span>
    <span class="na">project4</span><span class="pi">:</span> <span class="s">another without an image</span>
    <span class="na">project5</span><span class="pi">:</span> <span class="s">a project with a background image</span>
    <span class="na">project6</span><span class="pi">:</span> <span class="s">a project with no image</span>
  <span class="na">categories</span><span class="pi">:</span>
    <span class="na">fun</span><span class="pi">:</span> <span class="s">fun</span>
    <span class="na">work</span><span class="pi">:</span> <span class="s">work</span>
</code></pre></div></div> <p>Now, in <code class="language-plaintext highlighter-rouge">_pages/projects.md</code>, we need to get the correct category inside the loop, then its translation. For this, we’ll use the <code class="language-plaintext highlighter-rouge">capture</code> tag. The new code will be:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;h2 class="category"&gt;{{ category }}&lt;/h2&gt; --&gt;</span>
{% capture localized_category %}projects.categories.{{category}}{% endcapture %}
<span class="nt">&lt;h2</span> <span class="na">class=</span><span class="s">"category"</span><span class="nt">&gt;</span>{% t localized_category %}<span class="nt">&lt;/h2&gt;</span>
</code></pre></div></div> <p>Now, everything is localized. The projects overview page, the projects categories, and the projects pages.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/blog/2022-09-30-localized-projects/correct_localized_projects_overview-480.webp 480w,/assets/img/blog/2022-09-30-localized-projects/correct_localized_projects_overview-800.webp 800w,/assets/img/blog/2022-09-30-localized-projects/correct_localized_projects_overview-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/blog/2022-09-30-localized-projects/correct_localized_projects_overview.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <div class="caption"> Projects overview with localized categories. </div>]]></content><author><name></name></author><category term="website"/><category term="development"/><category term="al-folio"/><category term="website"/><category term="jekyll"/><category term="localization"/><category term="languages"/><summary type="html"><![CDATA[How to create localized Projects pages on your al-folio website.]]></summary></entry><entry><title type="html">Creating localized CV pages</title><link href="https://george-gca.github.io/blog/2022/localized-cv/" rel="alternate" type="text/html" title="Creating localized CV pages"/><published>2022-09-29T21:40:13+00:00</published><updated>2022-09-29T21:40:13+00:00</updated><id>https://george-gca.github.io/blog/2022/localized-cv</id><content type="html" xml:base="https://george-gca.github.io/blog/2022/localized-cv/"><![CDATA[<p>This post is part of a series of posts that explain how to set up your own site based on the al-folio theme and add support for a second language:</p> <ul> <li><a href="/blog/2022/running-local-al-folio/">Running locally your own al-folio website</a></li> <li><a href="/blog/2022/dual-language-al-folio/">Turning your al-folio into a dual-language website</a></li> <li>Creating localized CV pages</li> <li><a href="/blog/2022/localized-projects/">Creating localized Projects pages</a></li> <li><a href="/blog/2022/localized-blog/">Creating localized blog posts</a></li> </ul> <hr/> <p>We already <a href="/blog/2022/running-local-al-folio/">created a local al-folio website</a> and <a href="/blog/2022/dual-language-al-folio/">added support for another language in it</a>. If you look at the <code class="language-plaintext highlighter-rouge">cv</code> tab, it looks really nice, and can also give you the option to download a pdf file. Let’s see how we can create a localized (with a per language translation) version of it.</p> <h2 id="creating-the-structure">Creating the structure</h2> <p>The current structure of the cv page is composed of 3 main files: <code class="language-plaintext highlighter-rouge">_pages/cv.md</code>, <code class="language-plaintext highlighter-rouge">_layouts/cv.html</code>, and <code class="language-plaintext highlighter-rouge">_data/cv.yml</code>. The first one is the definition of the page, the second one is the layout of the page, and the third one is the data that is used to populate it. We will create a new folder for each language inside the <code class="language-plaintext highlighter-rouge">_data/</code> directory, and copy the file <code class="language-plaintext highlighter-rouge">_data/cv.yml</code> to both of them. The new <code class="language-plaintext highlighter-rouge">_data/</code> directory will look like this:</p> <ul> <li>_data/en/cv.yml</li> <li>_data/pt-br/cv.yml</li> <li>_data/coauthors.yml</li> <li>_data/repositories.yml</li> <li>_data/venues.yml</li> </ul> <p>Now, lets replace the content of the <code class="language-plaintext highlighter-rouge">_data/pt-br/cv.yml</code> file with the following:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Informações Gerais</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">map</span>
  <span class="na">contents</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Nome Completo</span>
      <span class="na">value</span><span class="pi">:</span> <span class="s">Albert Einstein</span>
    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Data de Nascimento</span>
      <span class="na">value</span><span class="pi">:</span> <span class="s">14 de março de </span><span class="m">1879</span>
    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Idiomas</span>
      <span class="na">value</span><span class="pi">:</span> <span class="s">Inglês, Alemão</span>

<span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Educação</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">time_table</span>
  <span class="na">contents</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">PhD</span>
      <span class="na">institution</span><span class="pi">:</span> <span class="s">University of Zurich, Zurique, Suíça</span>
      <span class="na">year</span><span class="pi">:</span> <span class="m">1905</span>
      <span class="na">description</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">Descrição 1.</span>
        <span class="pi">-</span> <span class="s">Descrição 2.</span>
        <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Descrição 3.</span>
          <span class="na">contents</span><span class="pi">:</span>
            <span class="pi">-</span> <span class="s">Sub-descrição 1.</span>
            <span class="pi">-</span> <span class="s">Sub-descrição 2.</span>
    <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Diploma de ensino federal</span>
      <span class="na">institution</span><span class="pi">:</span> <span class="s">Eidgenössische Technische Hochschule, Zurique, Suíça</span>
      <span class="na">year</span><span class="pi">:</span> <span class="m">1900</span>
      <span class="na">description</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">Descrição 1.</span>
        <span class="pi">-</span> <span class="s">Descrição 2.</span>

<span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Experiência</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">time_table</span>
  <span class="na">contents</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Professor de Física Teórica</span>
      <span class="na">institution</span><span class="pi">:</span> <span class="s">Institute for Advanced Study, Princeton University</span>
      <span class="na">year</span><span class="pi">:</span> <span class="s">1933 - </span><span class="m">1955</span>
      <span class="na">description</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">Descrição 1.</span>
        <span class="pi">-</span> <span class="s">Descrição 2.</span>
        <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Descrição 3.</span>
          <span class="na">contents</span><span class="pi">:</span>
            <span class="pi">-</span> <span class="s">Sub-descrição 1.</span>
            <span class="pi">-</span> <span class="s">Sub-descrição 2.</span>
    <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Visiting Professor</span>
      <span class="na">institution</span><span class="pi">:</span> <span class="s">California Institute of Technology, Pasadena, Califórnia, EUA</span>
      <span class="na">year</span><span class="pi">:</span> <span class="m">1933</span>
      <span class="na">description</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">Descrição 1.</span>
        <span class="pi">-</span> <span class="s">Descrição 2.</span>

    <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Diretor</span>
      <span class="na">institution</span><span class="pi">:</span> <span class="s">Kaiser Wilhelm Institute for Physics, Berlim, Alemanha.</span>
      <span class="na">year</span><span class="pi">:</span> <span class="s">1917-1933</span>

    <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Professor de Física Teórica</span>
      <span class="na">institution</span><span class="pi">:</span> <span class="s">Karl-Ferdinand University, Praga, Tchecoslováquia</span>
      <span class="na">year</span><span class="pi">:</span> <span class="s">1911 - </span><span class="m">1917</span>
      <span class="na">description</span><span class="pi">:</span>

    <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Professor Associado de Física Teórica</span>
      <span class="na">institution</span><span class="pi">:</span> <span class="s">University of Zurich, Zurique, Suíça</span>
      <span class="na">year</span><span class="pi">:</span> <span class="s">1909 - </span><span class="m">1911</span>

<span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Projetos de Código Aberto</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">time_table</span>
  <span class="na">contents</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">&lt;a href="https://github.com/alshedivat/al-folio"&gt;al-folio&lt;/a&gt;</span>
      <span class="na">year</span><span class="pi">:</span> <span class="s">2015-atual</span>
      <span class="na">description</span><span class="pi">:</span> <span class="s">Um tema Jekyll bonito, simples, limpo e responsivo para acadêmicos.</span>

<span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Honras e Prêmios</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">time_table</span>
  <span class="na">contents</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">year</span><span class="pi">:</span> <span class="m">1921</span>
      <span class="na">items</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">Prêmio Nobel de Física</span>
        <span class="pi">-</span> <span class="s">Medalha Matteucci</span>
    <span class="pi">-</span> <span class="na">year</span><span class="pi">:</span> <span class="m">2029</span>
      <span class="na">items</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">Medalha Max Planck</span>

<span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Interesses Acadêmicos</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">nested_list</span>
  <span class="na">contents</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Tópico 1.</span>
      <span class="na">items</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">Descrição 1.</span>
        <span class="pi">-</span> <span class="s">Descrição 2.</span>
    <span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Tópico 2.</span>
      <span class="na">items</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">Descrição 1.</span>
        <span class="pi">-</span> <span class="s">Descrição 2.</span>

<span class="pi">-</span> <span class="na">title</span><span class="pi">:</span> <span class="s">Outros Interesses</span>
  <span class="na">type</span><span class="pi">:</span> <span class="s">list</span>
  <span class="na">contents</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">&lt;u&gt;Hobbies:&lt;/u&gt; Hobby 1, Hobby 2, etc.</span>
</code></pre></div></div> <p>Now, open the <code class="language-plaintext highlighter-rouge">_layouts/cv.html</code> file and replace the following line:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- {% for entry in site.data.cv %} --&gt;</span>
{% for entry in site.data[site.lang].cv %}
</code></pre></div></div> <p>This will be sufficient to make the page work for the new language. Now, lets add the option to download the localized pdf file. For this, create a new folder for each language inside the <code class="language-plaintext highlighter-rouge">assets/pdf/</code> directory, and copy the file <code class="language-plaintext highlighter-rouge">assets/pdf/example_pdf.pdf</code> to both of them. The new <code class="language-plaintext highlighter-rouge">assets/pdf/</code> directory will look like this:</p> <ul> <li>assets/pdf/en/example_pdf.pdf</li> <li>assets/pdf/pt-br/example_pdf.pdf</li> <li>assets/pdf/example_pdf.pdf</li> </ul> <p>Now, lets update the link to the localized pdf file. We will use the same name for both files, which is already defined in the <code class="language-plaintext highlighter-rouge">cv_pdf: example_pdf.pdf</code> attribute inside <code class="language-plaintext highlighter-rouge">_pages/cv.md</code>. If you wish to use a different name for the pdfs, rename both and also update this information in the related attribute. Next, modify the following line in the <code class="language-plaintext highlighter-rouge">_layouts/cv.html</code> file:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;h1 class="post-title"&gt;{% t page.title %} {% if page.cv_pdf %}&lt;a href="{{ page.cv_pdf | prepend: 'assets/pdf/' | relative_url}}" target="_blank" rel="noopener noreferrer" class="float-right"&gt;&lt;i class="fas fa-file-pdf"&gt;&lt;/i&gt;&lt;/a&gt;{% endif %}&lt;/h1&gt; --&gt;</span>
<span class="nt">&lt;h1</span> <span class="na">class=</span><span class="s">"post-title"</span><span class="nt">&gt;</span>
  {% t page.title %} {% if page.cv_pdf %}<span class="nt">&lt;a</span>
    <span class="na">href=</span><span class="s">"{{ page.cv_pdf | prepend: '/' | prepend: site.lang | prepend: 'assets/pdf/' | relative_url}}"</span>
    <span class="na">target=</span><span class="s">"_blank"</span>
    <span class="na">rel=</span><span class="s">"noopener noreferrer"</span>
    <span class="na">class=</span><span class="s">"float-right"</span>
    <span class="nt">&gt;&lt;i</span> <span class="na">class=</span><span class="s">"fas fa-file-pdf"</span><span class="nt">&gt;&lt;/i&gt;&lt;/a</span>
  <span class="nt">&gt;</span>{% endif %}
<span class="nt">&lt;/h1&gt;</span>
</code></pre></div></div> <p>And that will do.</p>]]></content><author><name></name></author><category term="website"/><category term="development"/><category term="al-folio"/><category term="website"/><category term="jekyll"/><category term="localization"/><category term="languages"/><summary type="html"><![CDATA[How to create localized CV pages on your al-folio website.]]></summary></entry><entry><title type="html">Turning your al-folio into a dual-language website</title><link href="https://george-gca.github.io/blog/2022/dual-language-al-folio/" rel="alternate" type="text/html" title="Turning your al-folio into a dual-language website"/><published>2022-09-28T11:29:13+00:00</published><updated>2022-09-28T11:29:13+00:00</updated><id>https://george-gca.github.io/blog/2022/dual-language-al-folio</id><content type="html" xml:base="https://george-gca.github.io/blog/2022/dual-language-al-folio/"><![CDATA[<p>This post is part of a series of posts that explain how to set up your own site based on the al-folio theme and add support for a second language:</p> <ul> <li><a href="/blog/2022/running-local-al-folio/">Running locally your own al-folio website</a></li> <li>Turning your al-folio into a dual-language website</li> <li><a href="/blog/2022/localized-cv/">Creating localized CV pages</a></li> <li><a href="/blog/2022/localized-projects/">Creating localized Projects pages</a></li> <li><a href="/blog/2022/localized-blog/">Creating localized blog posts</a></li> </ul> <hr/> <p><a href="https://github.com/alshedivat/al-folio">al-folio</a> is a great theme for Jekyll websites. It is very customizable and easy to use, with support for blogging, repository information, projects, and more (see <a href="https://alshedivat.github.io/al-folio/">demo</a>). However, it does not support multiple languages out of the box. This post will show you how to add support for another language in your al-folio. I’ll add support for <code class="language-plaintext highlighter-rouge">pt-BR</code>, since it is my mother language. I’ll assume you have already <a href="/blog/2022/running-local-al-folio/">cloned your copy of the al-folio repository and have it running locally</a>.</p> <h2 id="installing-dependencies">Installing dependencies</h2> <p>We will do this with the help of the <a href="https://github.com/kurtsson/jekyll-multiple-languages-plugin">Jekyll Multiple Languages Plugin</a>. It adds i18n support for Jekyll. To install it, add the following line to your <code class="language-plaintext highlighter-rouge">Gemfile</code> under the <code class="language-plaintext highlighter-rouge">group :jekyll_plugins do</code>:</p> <div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">gem</span> <span class="s1">'jekyll-multiple-languages-plugin'</span>
</code></pre></div></div> <p>Also, add the following line to your <code class="language-plaintext highlighter-rouge">_config.yml</code> under <code class="language-plaintext highlighter-rouge">plugins:</code>:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="s">jekyll-multiple-languages-plugin</span>
</code></pre></div></div> <p>and the following lines after it (outside <code class="language-plaintext highlighter-rouge">plugins</code>), for example, before the <code class="language-plaintext highlighter-rouge">Jekyll Minifier</code> section:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># multi language settings</span>
<span class="na">languages</span><span class="pi">:</span> <span class="pi">[</span><span class="s2">"</span><span class="s">en"</span><span class="pi">,</span> <span class="s2">"</span><span class="s">pt-br"</span><span class="pi">]</span>
<span class="na">default_locale_in_subfolder</span><span class="pi">:</span> <span class="kc">false</span>
</code></pre></div></div> <p>Setting <code class="language-plaintext highlighter-rouge">default_locale_in_subfolder</code> to <code class="language-plaintext highlighter-rouge">false</code> will make your main language be the root of your website, instead of being in a subfolder. For example, instead of <code class="language-plaintext highlighter-rouge">https://george-gca.github.io/en/</code>, it will be <code class="language-plaintext highlighter-rouge">https://george-gca.github.io/</code>. This is the default behavior of al-folio, so we will keep it. The first language in the list will be the default language, English in this case. Then, run <code class="language-plaintext highlighter-rouge">bundle install</code> to install the plugin.</p> <h2 id="creating-translation-files">Creating translation files</h2> <p>Create a folder called <code class="language-plaintext highlighter-rouge">_i18n</code> and add sub-folders for each language, using the same names used on the <code class="language-plaintext highlighter-rouge">languages</code> setting on the <code class="language-plaintext highlighter-rouge">_config.yml</code> we just added. Also, create a <code class="language-plaintext highlighter-rouge">yml</code> file for each language. For example, for <code class="language-plaintext highlighter-rouge">pt-br</code>, create a folder called <code class="language-plaintext highlighter-rouge">_i18n/pt-br</code>. Then, create a file called <code class="language-plaintext highlighter-rouge">_i18n/pt-br.yml</code>. Our directory structure should look like this:</p> <ul> <li>_i18n/en.yml</li> <li>_i18n/pt-br.yml</li> <li>_i18n/en/</li> <li>_i18n/pt-br/</li> </ul> <h2 id="adding-language-toggle">Adding language toggle</h2> <p>Now, we need to add a language toggle to our website. We will add it to the navigation bar. Open the file <code class="language-plaintext highlighter-rouge">_includes/header.html</code> and add the following code before the <code class="language-plaintext highlighter-rouge">Toogle theme mode</code> area:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- Toogle language --&gt;</span>
<span class="nt">&lt;li</span> <span class="na">class=</span><span class="s">"nav-item active"</span><span class="nt">&gt;</span>
  {% if site.lang == "en" %}
  <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"nav-link"</span> <span class="na">href=</span><span class="s">"{{site.baseurl_root}}/pt-br{{page.url}}"</span><span class="nt">&gt;</span> PT-BR <span class="nt">&lt;/a&gt;</span>
  {% elsif site.lang == "pt-br" %}
  <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"nav-link"</span> <span class="na">href=</span><span class="s">"{{site.baseurl_root}}{{page.url}}"</span><span class="nt">&gt;</span> EN <span class="nt">&lt;/a&gt;</span>
  {% endif %}
<span class="nt">&lt;/li&gt;</span>
</code></pre></div></div> <p>This will add a link to the other language. The <code class="language-plaintext highlighter-rouge">page.url</code> will keep the current page, so the user will not be redirected to the home page. Note that <code class="language-plaintext highlighter-rouge">site.baseurl_root</code> is a variable introduced by the Jekyll Multiple Languages Plugin, and it points to the root of the page without the language path. More information about the newly added variables can be found <a href="https://github.com/kurtsson/jekyll-multiple-languages-plugin#55-link-between-languages">here</a>.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/blog/2022-09-28-dual-language-al-folio/header_en-480.webp 480w,/assets/img/blog/2022-09-28-dual-language-al-folio/header_en-800.webp 800w,/assets/img/blog/2022-09-28-dual-language-al-folio/header_en-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/blog/2022-09-28-dual-language-al-folio/header_en.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <div class="caption"> Header with language toggle. </div> <h2 id="adding-translated-titles">Adding translated titles</h2> <p>Until now, we added everything we needed to support the translation, but haven’t done the translation per se. We will start that now. Open the file <code class="language-plaintext highlighter-rouge">_i18n/en.yml</code> and add the following lines:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">titles</span><span class="pi">:</span>
  <span class="na">about</span><span class="pi">:</span> <span class="s">about</span>
  <span class="na">blog</span><span class="pi">:</span> <span class="s">blog</span>
  <span class="na">cv</span><span class="pi">:</span> <span class="s">cv</span>
  <span class="na">news</span><span class="pi">:</span> <span class="s">news</span>
  <span class="na">projects</span><span class="pi">:</span> <span class="s">projects</span>
  <span class="na">publications</span><span class="pi">:</span> <span class="s">publications</span>
  <span class="na">repositories</span><span class="pi">:</span> <span class="s">repositories</span>
  <span class="na">teaching</span><span class="pi">:</span> <span class="s">teaching</span>
  <span class="na">submenus</span><span class="pi">:</span> <span class="s">submenus</span>
  <span class="na">unk</span><span class="pi">:</span> <span class="s">page not found</span>
</code></pre></div></div> <p>This will add the titles for the pages. Now, open the file <code class="language-plaintext highlighter-rouge">_i18n/pt-br.yml</code> and add the following lines:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">titles</span><span class="pi">:</span>
  <span class="na">about</span><span class="pi">:</span> <span class="s">sobre</span>
  <span class="na">blog</span><span class="pi">:</span> <span class="s">blog</span>
  <span class="na">cv</span><span class="pi">:</span> <span class="s">cv</span>
  <span class="na">news</span><span class="pi">:</span> <span class="s">novidades</span>
  <span class="na">projects</span><span class="pi">:</span> <span class="s">projetos</span>
  <span class="na">publications</span><span class="pi">:</span> <span class="s">publicações</span>
  <span class="na">repositories</span><span class="pi">:</span> <span class="s">repositórios</span>
  <span class="na">teaching</span><span class="pi">:</span> <span class="s">ensino</span>
  <span class="na">submenus</span><span class="pi">:</span> <span class="s">submenus</span>
  <span class="na">unk</span><span class="pi">:</span> <span class="s">página não encontrada</span>
</code></pre></div></div> <p>This will add the titles for the pages in Portuguese. Now that we have the translated titles, we have to tell the pages to use these instead of the hardcoded ones. To do so, open all the pages under the <code class="language-plaintext highlighter-rouge">_pages</code> folder and change their title to use the correct <code class="language-plaintext highlighter-rouge">titles</code> variable. For example, the new title for the <code class="language-plaintext highlighter-rouge">about.md</code> page should look like this:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">title</span><span class="pi">:</span> <span class="s">titles.about</span>
</code></pre></div></div> <p>If you run your website now, you’ll see that the titles are shown as <code class="language-plaintext highlighter-rouge">titles.about</code> instead of just <code class="language-plaintext highlighter-rouge">about</code> as it was supposed to, since its default is in English. We still need to tell the html templates to select the correct translated version of these variables. To do so, open the file <code class="language-plaintext highlighter-rouge">_includes/header.html</code> and change all the <code class="language-plaintext highlighter-rouge">title</code> variables to use the <a href="https://github.com/kurtsson/jekyll-multiple-languages-plugin#51-translating-strings">t function</a>. The <code class="language-plaintext highlighter-rouge">t</code> function, or its longer version <code class="language-plaintext highlighter-rouge">translate</code>, will ensure that it will select the correct version from the current language yml file. More specifically, do the following changes:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;a class="nav-link" href="{{ '/' | relative_url }}"&gt;{{ about_title }} --&gt;</span>
<span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"nav-link"</span> <span class="na">href=</span><span class="s">"{{ '/' | relative_url }}"</span>
  <span class="nt">&gt;</span>{% t about_title %}

  <span class="c">&lt;!-- &lt;a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"&gt;{{ p.title }} --&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"nav-link dropdown-toggle"</span> <span class="na">href=</span><span class="s">"#"</span> <span class="na">id=</span><span class="s">"navbarDropdown"</span> <span class="na">role=</span><span class="s">"button"</span> <span class="na">data-toggle=</span><span class="s">"dropdown"</span> <span class="na">aria-haspopup=</span><span class="s">"true"</span> <span class="na">aria-expanded=</span><span class="s">"false"</span>
    <span class="nt">&gt;</span>{% t p.title %}

    <span class="c">&lt;!-- &lt;a class="dropdown-item" href="{{ child.permalink | relative_url }}"&gt;{{ child.title }}&lt;/a&gt; --&gt;</span>
    <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"dropdown-item"</span> <span class="na">href=</span><span class="s">"{{ child.permalink | relative_url }}"</span><span class="nt">&gt;</span>{% t child.title %}<span class="nt">&lt;/a&gt;</span>

    <span class="c">&lt;!-- &lt;a class="nav-link" href="{{ p.url | relative_url }}"&gt;{{ p.title }} --&gt;</span>
    <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"nav-link"</span> <span class="na">href=</span><span class="s">"{{ p.url | relative_url }}"</span><span class="nt">&gt;</span>{% t p.title %}<span class="nt">&lt;/a&gt;&lt;/a</span>
  <span class="nt">&gt;&lt;/a</span>
<span class="nt">&gt;</span>
</code></pre></div></div> <p>Now run your website again and you’ll see that the titles have the correct values. You can even change the language on the toggle and see that the titles change accordingly.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/blog/2022-09-28-dual-language-al-folio/header_pt-br-480.webp 480w,/assets/img/blog/2022-09-28-dual-language-al-folio/header_pt-br-800.webp 800w,/assets/img/blog/2022-09-28-dual-language-al-folio/header_pt-br-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/blog/2022-09-28-dual-language-al-folio/header_pt-br.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <div class="caption"> Header in Portuguese. </div> <h2 id="fixing-translated-navigation">Fixing translated navigation</h2> <p>Everything seems to work fine, except not. If you click in the <code class="language-plaintext highlighter-rouge">PT-BR</code> toggle in the header, then click in another page (e.g. repositories), it will change again the titles to English. To handle this kind of situation, we have to make sure that when the user clicks the header links, it will keep the language. Lets do this first for the <code class="language-plaintext highlighter-rouge">about</code> page. To do so, open the file <code class="language-plaintext highlighter-rouge">_includes/header.html</code> and change the link to the <code class="language-plaintext highlighter-rouge">about</code> page to use the <code class="language-plaintext highlighter-rouge">site.baseurl</code> variable instead of the <code class="language-plaintext highlighter-rouge">relative_url</code>. More specifically, do the following changes:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;a class="nav-link" href="{{ '/' | relative_url }}"&gt;{% t about_title %} --&gt;</span>
<span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"nav-link"</span> <span class="na">href=</span><span class="s">"{{ '/' | prepend: site.baseurl}}"</span><span class="nt">&gt;</span>{% t about_title %}<span class="nt">&lt;/a&gt;</span>
</code></pre></div></div> <p>Now, if you are in another page, for example, the <code class="language-plaintext highlighter-rouge">repositories</code> page, and click in the <code class="language-plaintext highlighter-rouge">PT-BR</code> toggle, then click in the <code class="language-plaintext highlighter-rouge">about</code> page, it will keep the language in the titles. Now, let’s enable this for all the other pages. To do so, open the file <code class="language-plaintext highlighter-rouge">_includes/header.html</code> again and do the following changes:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;a class="nav-link" href="{{ '/blog/' | relative_url }}"&gt;{{ site.blog_nav_title }} --&gt;</span>
<span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"nav-link"</span> <span class="na">href=</span><span class="s">"{{ '/blog/' | prepend: site.baseurl }}"</span>
  <span class="nt">&gt;</span>{{ site.blog_nav_title }}

  <span class="c">&lt;!-- &lt;a class="dropdown-item" href="{{ child.permalink | relative_url }}"&gt;{% t child.title %}&lt;/a&gt; --&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"dropdown-item"</span> <span class="na">href=</span><span class="s">"{{ child.permalink | prepend: site.baseurl }}"</span><span class="nt">&gt;</span>{% t child.title %}<span class="nt">&lt;/a&gt;</span>

  <span class="c">&lt;!-- &lt;a class="nav-link" href="{{ p.url | relative_url }}"&gt;{% t p.title %} --&gt;</span>
  <span class="nt">&lt;a</span> <span class="na">class=</span><span class="s">"nav-link"</span> <span class="na">href=</span><span class="s">"{{ p.url | prepend: site.baseurl }}"</span><span class="nt">&gt;</span>{% t p.title %}<span class="nt">&lt;/a&gt;&lt;/a</span>
<span class="nt">&gt;</span>
</code></pre></div></div> <h2 id="adding-translated-titles-inside-the-pages">Adding translated titles inside the pages</h2> <p>Now everything is working fine! The sun is rising, and the world is colorful again :rainbow:. But wait, there is still stuff missing. If you click in the <code class="language-plaintext highlighter-rouge">PT-BR</code> toggle, then click in the <code class="language-plaintext highlighter-rouge">publicações</code> page, you’ll see that the title of the page is still <code class="language-plaintext highlighter-rouge">titles.publications</code>.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/blog/2022-09-28-dual-language-al-folio/publications_title_wrong-480.webp 480w,/assets/img/blog/2022-09-28-dual-language-al-folio/publications_title_wrong-800.webp 800w,/assets/img/blog/2022-09-28-dual-language-al-folio/publications_title_wrong-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/blog/2022-09-28-dual-language-al-folio/publications_title_wrong.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <div class="caption"> What should be a translated title. </div> <p>Oh crap, will this ever end someday? :scream: Well, yes, it will. We just need to tell the pages to use the correct translated title. To do so, let’s see which templates do the pages use. The page <code class="language-plaintext highlighter-rouge">publications</code> for example, which is located in file <code class="language-plaintext highlighter-rouge">_pages/publications.md</code>, uses the template <code class="language-plaintext highlighter-rouge">page</code>, as can be seen by the following line in the beginning of the file:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">layout</span><span class="pi">:</span> <span class="s">page</span>
</code></pre></div></div> <p>So, lets open the file <code class="language-plaintext highlighter-rouge">_layouts/page.html</code> and change the title to use the <code class="language-plaintext highlighter-rouge">t</code> function. More specifically, do the following changes:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;h1 class="post-title"&gt;{{ page.title }}&lt;/h1&gt; --&gt;</span>
<span class="nt">&lt;h1</span> <span class="na">class=</span><span class="s">"post-title"</span><span class="nt">&gt;</span>{% t page.title %}<span class="nt">&lt;/h1&gt;</span>
</code></pre></div></div> <p>Now, if you run your website, it will not work. This happens because the <code class="language-plaintext highlighter-rouge">t</code> function is now trying to translate a variable that is not defined. But where? If you do a little search, you’ll notice that the <code class="language-plaintext highlighter-rouge">publications</code> page is not the only one that uses the <code class="language-plaintext highlighter-rouge">layout: page</code>. All pages that use it are:</p> <ul> <li>404.html</li> <li>news.html</li> <li>_pages/dropdown.md</li> <li>_pages/projects.md</li> <li>_pages/publications.md</li> <li>_pages/repositories.md</li> <li>_pages/teaching.md</li> <li>_projects/1_project.md</li> <li>_projects/2_project.md</li> <li>_projects/3_project.md</li> <li>_projects/4_project.md</li> <li>_projects/5_project.md</li> <li>_projects/6_project.md</li> </ul> <p>You need to change the <code class="language-plaintext highlighter-rouge">title</code> for <strong>ALL</strong> these pages. We already did it for the pages inside <code class="language-plaintext highlighter-rouge">_pages/</code>, so let’s do it for the rest. Open the file <code class="language-plaintext highlighter-rouge">404.html</code> and change its <code class="language-plaintext highlighter-rouge">title: "Page not found"</code> to <code class="language-plaintext highlighter-rouge">title: titles.unk</code>, since we already defined <code class="language-plaintext highlighter-rouge">titles.unk</code> in both <code class="language-plaintext highlighter-rouge">_i18n/en.yml</code> and <code class="language-plaintext highlighter-rouge">_i18n/pt-br.yml</code>. To keep the projects section more organized, let’s create new attributes for it inside each of the translation files. So, the new <code class="language-plaintext highlighter-rouge">_i18n/en.yml</code> and <code class="language-plaintext highlighter-rouge">_i18n/pt-br.yml</code> will look like this, respectively:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">titles</span><span class="pi">:</span>
  <span class="na">about</span><span class="pi">:</span> <span class="s">about</span>
  <span class="na">blog</span><span class="pi">:</span> <span class="s">blog</span>
  <span class="na">cv</span><span class="pi">:</span> <span class="s">cv</span>
  <span class="na">news</span><span class="pi">:</span> <span class="s">news</span>
  <span class="na">projects</span><span class="pi">:</span> <span class="s">projects</span>
  <span class="na">publications</span><span class="pi">:</span> <span class="s">publications</span>
  <span class="na">repositories</span><span class="pi">:</span> <span class="s">repositories</span>
  <span class="na">teaching</span><span class="pi">:</span> <span class="s">teaching</span>
  <span class="na">submenus</span><span class="pi">:</span> <span class="s">submenus</span>
  <span class="na">unk</span><span class="pi">:</span> <span class="s">page not found</span>
<span class="na">projects</span><span class="pi">:</span>
  <span class="na">titles</span><span class="pi">:</span>
    <span class="na">project1</span><span class="pi">:</span> <span class="s">Project </span><span class="m">1</span>
    <span class="na">project2</span><span class="pi">:</span> <span class="s">Project </span><span class="m">2</span>
    <span class="na">project3</span><span class="pi">:</span> <span class="s">Project </span><span class="m">3</span>
    <span class="na">project4</span><span class="pi">:</span> <span class="s">Project </span><span class="m">4</span>
    <span class="na">project5</span><span class="pi">:</span> <span class="s">Project </span><span class="m">5</span>
    <span class="na">project6</span><span class="pi">:</span> <span class="s">Project </span><span class="m">6</span>
</code></pre></div></div> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">titles</span><span class="pi">:</span>
  <span class="na">about</span><span class="pi">:</span> <span class="s">sobre</span>
  <span class="na">blog</span><span class="pi">:</span> <span class="s">blog</span>
  <span class="na">cv</span><span class="pi">:</span> <span class="s">cv</span>
  <span class="na">news</span><span class="pi">:</span> <span class="s">novidades</span>
  <span class="na">projects</span><span class="pi">:</span> <span class="s">projetos</span>
  <span class="na">publications</span><span class="pi">:</span> <span class="s">publicações</span>
  <span class="na">repositories</span><span class="pi">:</span> <span class="s">repositórios</span>
  <span class="na">teaching</span><span class="pi">:</span> <span class="s">ensino</span>
  <span class="na">submenus</span><span class="pi">:</span> <span class="s">submenus</span>
  <span class="na">unk</span><span class="pi">:</span> <span class="s">página não encontrada</span>
<span class="na">projects</span><span class="pi">:</span>
  <span class="na">titles</span><span class="pi">:</span>
    <span class="na">project1</span><span class="pi">:</span> <span class="s">Projeto </span><span class="m">1</span>
    <span class="na">project2</span><span class="pi">:</span> <span class="s">Projeto </span><span class="m">2</span>
    <span class="na">project3</span><span class="pi">:</span> <span class="s">Projeto </span><span class="m">3</span>
    <span class="na">project4</span><span class="pi">:</span> <span class="s">Projeto </span><span class="m">4</span>
    <span class="na">project5</span><span class="pi">:</span> <span class="s">Projeto </span><span class="m">5</span>
    <span class="na">project6</span><span class="pi">:</span> <span class="s">Projeto </span><span class="m">6</span>
</code></pre></div></div> <p>Now, all we have to do is open all the files inside <code class="language-plaintext highlighter-rouge">_projects/</code> and change its titles. For the file <code class="language-plaintext highlighter-rouge">_projects/1_project.md</code>, for example, will look like this:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">title</span><span class="pi">:</span> <span class="s">projects.titles.project1</span>
</code></pre></div></div> <p>Finally, we can run our website again and it will work as expected. :tada:.</p> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/blog/2022-09-28-dual-language-al-folio/publications_title_fixed-480.webp 480w,/assets/img/blog/2022-09-28-dual-language-al-folio/publications_title_fixed-800.webp 800w,/assets/img/blog/2022-09-28-dual-language-al-folio/publications_title_fixed-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/blog/2022-09-28-dual-language-al-folio/publications_title_fixed.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <div class="caption"> Now THIS is a translated title. </div> <p>Don’t forget to do the same for the other pages that use different layouts, like <code class="language-plaintext highlighter-rouge">cv</code>. Open the file <code class="language-plaintext highlighter-rouge">_layouts/cv.html</code> and modify:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!-- &lt;h1 class="post-title"&gt;{{ page.title }} {% if page.cv_pdf %}&lt;a href="{{ page.cv_pdf | prepend: 'assets/pdf/' | relative_url}}" target="_blank" rel="noopener noreferrer" class="float-right"&gt;&lt;i class="fas fa-file-pdf"&gt;&lt;/i&gt;&lt;/a&gt;{% endif %}&lt;/h1&gt; --&gt;</span>
<span class="nt">&lt;h1</span> <span class="na">class=</span><span class="s">"post-title"</span><span class="nt">&gt;</span>
  {% t page.title %} {% if page.cv_pdf %}<span class="nt">&lt;a</span>
    <span class="na">href=</span><span class="s">"{{ page.cv_pdf | prepend: 'assets/pdf/' | relative_url}}"</span>
    <span class="na">target=</span><span class="s">"_blank"</span>
    <span class="na">rel=</span><span class="s">"noopener noreferrer"</span>
    <span class="na">class=</span><span class="s">"float-right"</span>
    <span class="nt">&gt;&lt;i</span> <span class="na">class=</span><span class="s">"fas fa-file-pdf"</span><span class="nt">&gt;&lt;/i&gt;&lt;/a</span>
  <span class="nt">&gt;</span>{% endif %}
<span class="nt">&lt;/h1&gt;</span>
</code></pre></div></div> <h2 id="adding-translated-content">Adding translated content</h2> <p>Now, let’s see how to add translated content. For example, let’s say that we want to translate the biography in the <code class="language-plaintext highlighter-rouge">about</code> page. The best way to achieve this is to create translated parts of the pages for each language, and then import the correct version. For this, cut the whole biography part of the <code class="language-plaintext highlighter-rouge">about</code> page (<code class="language-plaintext highlighter-rouge">_pages/about.md</code>), leaving only the header. Then, create a new file <code class="language-plaintext highlighter-rouge">_i18n/en/pages/about.md</code> and paste the content there. Do the same for the file <code class="language-plaintext highlighter-rouge">_i18n/pt-br/pages/about.md</code>, but adding the translated version. Now, in the file <code class="language-plaintext highlighter-rouge">_pages/about.md</code>, add the <a href="https://github.com/kurtsson/jekyll-multiple-languages-plugin#52-including-translated-files">translate_file</a> function, pointing to the new about files. The final <code class="language-plaintext highlighter-rouge">_pages/about.md</code> will look like this:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code>---
layout: about
title: titles.about
subtitle: <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">'#'</span><span class="nt">&gt;</span>Affiliations<span class="nt">&lt;/a&gt;</span>. Address. Contacts. Moto. Etc.
permalink: /

profile:
  align: right
  image: prof_pic.jpg
  image_circular: false # crops the image to make it circular
  address: &gt;
    <span class="nt">&lt;p&gt;</span>555 your office number<span class="nt">&lt;/p&gt;</span>
    <span class="nt">&lt;p&gt;</span>123 your address street<span class="nt">&lt;/p&gt;</span>
    <span class="nt">&lt;p&gt;</span>Your City, State 12345<span class="nt">&lt;/p&gt;</span>

news: true # includes a list of news items
selected_papers: true # includes a list of papers marked as "selected={true}"
social: true # includes social icons at the bottom of the page
---

{% translate_file pages/about.md %}
</code></pre></div></div> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/blog/2022-09-28-dual-language-al-folio/about_pt-br-480.webp 480w,/assets/img/blog/2022-09-28-dual-language-al-folio/about_pt-br-800.webp 800w,/assets/img/blog/2022-09-28-dual-language-al-folio/about_pt-br-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/blog/2022-09-28-dual-language-al-folio/about_pt-br.png" class="img-fluid rounded z-depth-1 mx-auto d-block" width="100%" height="auto" data-zoomable="" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <div class="caption"> Biography in Portuguese. </div> <h2 id="fixing-page-title-in-the-browser">Fixing page title in the browser</h2> <p>Currently, when you open a section of your site, in the browser tab the section name is not translated. To solve this, open the file <code class="language-plaintext highlighter-rouge">_includes/metadata.html</code> and change the following code:</p> <div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">if</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s1">'/blog/index.html'</span><span class="w"> </span><span class="cp">%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">site</span><span class="p">.</span><span class="nv">blog_nav_title</span><span class="w"> </span><span class="cp">}}</span> | <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">elsif</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s1">'blank'</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s1">'/'</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span> | <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">else</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">endif</span><span class="w"> </span><span class="cp">-%}</span>
</code></pre></div></div> <p>for this code:</p> <div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">if</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s1">'/blog/index.html'</span><span class="w"> </span><span class="cp">%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">site</span><span class="p">.</span><span class="nv">blog_nav_title</span><span class="w"> </span><span class="cp">}}</span> | <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%</span><span class="w"> </span><span class="nt">elsif</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="ow">contains</span><span class="w"> </span><span class="s1">'/blog/'</span><span class="w"> </span><span class="cp">%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span> | <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">elsif</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="ow">contains</span><span class="w"> </span><span class="s1">'Announcement'</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">elsif</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s1">'blank'</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">url</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s1">'/'</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{%</span><span class="w"> </span><span class="nt">t</span><span class="w"> </span><span class="nv">page</span><span class="p">.</span><span class="nv">title</span><span class="w"> </span><span class="cp">%}</span> | <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">else</span><span class="w"> </span><span class="cp">-%}</span>
  <span class="cp">{{</span><span class="w"> </span><span class="nv">title</span><span class="w"> </span><span class="cp">}}</span>
<span class="cp">{%-</span><span class="w"> </span><span class="nt">endif</span><span class="w"> </span><span class="cp">-%}</span>
</code></pre></div></div> <p>This will trigger another problem, caused by the title of the second news in the about page. We need to add a translated title for this new. Now, do the following changes:</p> <p>File <code class="language-plaintext highlighter-rouge">_news/announcement_2.md</code>:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># title: A long announcement with details</span>
<span class="na">title</span><span class="pi">:</span> <span class="s">news.titles.news2</span>
</code></pre></div></div> <p>File <code class="language-plaintext highlighter-rouge">_i18n/en.yml</code>:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">news</span><span class="pi">:</span>
  <span class="na">titles</span><span class="pi">:</span>
    <span class="na">news2</span><span class="pi">:</span> <span class="s">A long announcement with details</span>
</code></pre></div></div> <p>File <code class="language-plaintext highlighter-rouge">_i18n/pt-br.yml</code>:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">news</span><span class="pi">:</span>
  <span class="na">titles</span><span class="pi">:</span>
    <span class="na">news2</span><span class="pi">:</span> <span class="s">Um anúncio longo com detalhes</span>
</code></pre></div></div> <h2 id="summing-up">Summing up</h2> <p>Adding a translated version of your site is not hard, but it is kind of annoying. Even with the help of this <a href="https://github.com/kurtsson/jekyll-multiple-languages-plugin">great plugin</a>, there are some little details that, if missed, will take a lot of time and patience to master (at least took me). There are a few things that can be done also, like translating the description of the pages and more of their content, but since these can be done based on the same concepts that I showed here, I’ll leave it as a homework :laughing:. I will detail how to create translated versions of your cv and blog in other posts, since this one is already really long. I hope this post was useful to you. If you have any questions, feel free to ask in the comments.</p>]]></content><author><name></name></author><category term="website"/><category term="development"/><category term="al-folio"/><category term="website"/><category term="jekyll"/><category term="localization"/><category term="languages"/><summary type="html"><![CDATA[Adding support for another language in your al-folio.]]></summary></entry><entry><title type="html">Running locally your own al-folio website</title><link href="https://george-gca.github.io/blog/2022/running-local-al-folio/" rel="alternate" type="text/html" title="Running locally your own al-folio website"/><published>2022-09-27T22:13:16+00:00</published><updated>2022-09-27T22:13:16+00:00</updated><id>https://george-gca.github.io/blog/2022/running-local-al-folio</id><content type="html" xml:base="https://george-gca.github.io/blog/2022/running-local-al-folio/"><![CDATA[<p>This post is part of a series of posts that explain how to set up your own site based on the al-folio theme and add support for a second language:</p> <ul> <li>Running locally your own al-folio website</li> <li><a href="/blog/2022/dual-language-al-folio/">Turning your al-folio into a dual-language website</a></li> <li><a href="/blog/2022/localized-cv/">Creating localized CV pages</a></li> <li><a href="/blog/2022/localized-projects/">Creating localized Projects pages</a></li> <li><a href="/blog/2022/localized-blog/">Creating localized blog posts</a></li> </ul> <hr/> <p>I decided to write this post because I had a hard time figuring out how to run my own Jekyll page locally, especially since I don’t regularly use Jekyll. I hope this post will help you to run your own <a href="https://alshedivat.github.io/al-folio/">al-folio</a> website locally, or whatever other Jekyll-based theme you have.</p> <h2 id="installing-ruby-and-rbenv">Installing Ruby and rbenv</h2> <p>I ran my code in a native Linux environment (Ubuntu 22.04.1 LTS), but I tested it in a <a href="https://learn.microsoft.com/en-us/windows/wsl/install">WSL environment</a> as well. First things first: you need to install Ruby language support. The <a href="https://github.com/alshedivat/al-folio#local-setup-standard">recommended way</a> by the al-folio creators is using <a href="https://github.com/rbenv/rbenv">rbenv</a>. For those familiar with Python, <code class="language-plaintext highlighter-rouge">rbenv</code> is similar to <code class="language-plaintext highlighter-rouge">pyenv</code>. To install <code class="language-plaintext highlighter-rouge">rbenv</code>, run the following commands:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/rbenv/rbenv.git ~/.rbenv
<span class="nb">cd</span> ~/.rbenv <span class="o">&amp;&amp;</span> src/configure <span class="o">&amp;&amp;</span> make <span class="nt">-C</span> src
</code></pre></div></div> <p>This will download the <code class="language-plaintext highlighter-rouge">rbenv</code> repository to your home directory, and then compile it. <strong>DON’T</strong> install it via <code class="language-plaintext highlighter-rouge">apt</code>, since it will download an older version of the package, and will not allow you to install the latest Ruby versions. Next, add the following lines to your <code class="language-plaintext highlighter-rouge">~/.bashrc</code> file:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># enable rbenv</span>
<span class="k">if</span> <span class="o">[</span> <span class="nt">-d</span> <span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.rbenv/"</span> <span class="o">]</span><span class="p">;</span> <span class="k">then
    </span><span class="nb">export </span><span class="nv">PATH</span><span class="o">=</span><span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.rbenv/bin:</span><span class="nv">$PATH</span><span class="s2">"</span>
    <span class="nb">eval</span> <span class="s2">"</span><span class="si">$(</span>rbenv init - bash<span class="si">)</span><span class="s2">"</span>
<span class="k">fi</span>
</code></pre></div></div> <p>Then, restart your terminal or run <code class="language-plaintext highlighter-rouge">. ~/.bashrc</code> to reload your bash settings. This will make the <code class="language-plaintext highlighter-rouge">rbenv</code> command available in your terminal. To test if this is working properly, run <code class="language-plaintext highlighter-rouge">curl -fsSL https://github.com/rbenv/rbenv-installer/raw/main/bin/rbenv-doctor | bash</code>. It should output something similar to this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Checking for `rbenv' in PATH: /home/gca/.rbenv/bin/rbenv
Checking for rbenv shims in PATH: Not found
Checking `rbenv install' support: /home/gca/.rbenv/plugins/ruby-build/bin/rbenv-install (ruby-build 20220910.1-10-gecb9d22)
Counting installed Ruby versions: 1 versions
Auditing installed plugins: OK
</code></pre></div></div> <p>It will display an error in line <code class="language-plaintext highlighter-rouge">Checking for rbenv shims in PATH</code>. Don’t worry, this will be fixed. Next, you need to install <a href="https://github.com/rbenv/ruby-build">ruby-build</a> as a <code class="language-plaintext highlighter-rouge">rbenv</code> plugin, so you can easily download and install different versions of Ruby. To do so, run the following commands:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir</span> <span class="nt">-p</span> <span class="s2">"</span><span class="si">$(</span>rbenv root<span class="si">)</span><span class="s2">"</span>/plugins
git clone https://github.com/rbenv/ruby-build.git <span class="s2">"</span><span class="si">$(</span>rbenv root<span class="si">)</span><span class="s2">"</span>/plugins/ruby-build
</code></pre></div></div> <p>To check which versions of Ruby are available to install, simply run <code class="language-plaintext highlighter-rouge">rbenv install --list</code>. You can install any version you want, but I recommend installing the latest stable version. At the time of writing, it is version 3.1.2. To install it, you need first to install the ssl dependency and then the Ruby version.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>apt <span class="nb">install</span> <span class="nt">-y</span> libssl-dev
rbenv <span class="nb">install </span>3.1.2
</code></pre></div></div> <h2 id="installing-al-folio-dependencies">Installing al-folio dependencies</h2> <p>Now that you have Ruby installed, you can install al-folio dependencies. First, clone the al-folio repository to your local machine. Then, enter the repository directory and create a local Ruby environment with the installed Ruby version. Next, install the <code class="language-plaintext highlighter-rouge">bundle</code> package, so it will take care of installing the rest of the dependencies. To do all of this, run the following commands:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone ~/git@github.com:alshedivat/al-folio.git
<span class="nb">cd</span> ~/al-folio
rbenv <span class="nb">local </span>3.1.2
gem <span class="nb">install </span>bundle
bundle <span class="nb">install</span>
</code></pre></div></div> <p>Since al-folio supports <code class="language-plaintext highlighter-rouge">jupyter</code> notebooks, we also need to install it. If you are not planning to use notebooks that much, you can install it via <a href="https://github.com/pypa/pipx">pipx</a>. To install both <code class="language-plaintext highlighter-rouge">pipx</code> and <code class="language-plaintext highlighter-rouge">jupyter</code>, run the following commands:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># this can also be done via apt with `sudo apt install -y pipx`</span>
python3 <span class="nt">-m</span> pip <span class="nb">install</span> <span class="nt">--user</span> pipx
pipx <span class="nb">install </span>jupyter
</code></pre></div></div> <h2 id="running-al-folio-locally">Running al-folio locally</h2> <p>From now on, you can run the site locally. All you need to do is to open the al-folio directory and call Jekyll:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bundle <span class="nb">exec </span>jekyll serve <span class="nt">--lsi</span>
</code></pre></div></div> <p>Happy coding!</p>]]></content><author><name></name></author><category term="website"/><category term="development"/><category term="al-folio"/><category term="website"/><category term="jekyll"/><category term="local"/><summary type="html"><![CDATA[Step by step on how to run your own al-folio locally.]]></summary></entry></feed>