<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Cariad Eccleston</title>
    <description>The latest articles on DEV Community by Cariad Eccleston (@cariad).</description>
    <link>https://dev.to/cariad</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F611860%2Fadc4f79b-8c9c-4346-9f61-60241fac7a45.jpeg</url>
      <title>DEV Community: Cariad Eccleston</title>
      <link>https://dev.to/cariad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cariad"/>
    <language>en</language>
    <item>
      <title>Drawing blocks on the command-line with Python</title>
      <dc:creator>Cariad Eccleston</dc:creator>
      <pubDate>Sun, 11 Apr 2021 08:59:14 +0000</pubDate>
      <link>https://dev.to/cariad/drawing-blocks-on-the-command-line-with-python-3pn7</link>
      <guid>https://dev.to/cariad/drawing-blocks-on-the-command-line-with-python-3pn7</guid>
      <description>&lt;p&gt;Hey folks! I just joined the community here, and I thought I'd share an interesting little rabbit hole I recently fell down.&lt;/p&gt;

&lt;h2&gt;
  
  
  The goal
&lt;/h2&gt;

&lt;p&gt;A couple of weeks ago, I released &lt;a href="https://github.com/cariad/progrow"&gt;progrow&lt;/a&gt;; a Python package for drawing progress bars on the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apple harvest   █▎                     1 /   9 •  11%
banana harvest  ██                     9 /  99 •   9%
caramel harvest ███████████████████▉ 100 / 100 • 100%
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The package does a couple of cool things, but I'm going to focus on my approach to drawing the bar.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first shot
&lt;/h2&gt;

&lt;p&gt;My original plan for the bar was just to calculate the amount of space available then fill the correct percentage of it with the Unicode "full block" (&lt;code&gt;█&lt;/code&gt;) character.&lt;/p&gt;

&lt;p&gt;So, for example, a bar of length &lt;strong&gt;10&lt;/strong&gt; and percentage &lt;strong&gt;0.5&lt;/strong&gt; (with &lt;strong&gt;0.0&lt;/strong&gt; being 0% and &lt;strong&gt;1.0&lt;/strong&gt; being 100%) would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[█████     ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's some code that fulfills that rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;decimal&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;

&lt;span class="n"&gt;EMPTY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;"""
    Returns a string describing a bar "length" characters long
    and filled to "pc" percent (0.0 to 1.0).
    """&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EMPTY&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Percentage of the length that each element represents:
&lt;/span&gt;    &lt;span class="n"&gt;element_pc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;length&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Take a slice of the percentage for this element:
&lt;/span&gt;        &lt;span class="n"&gt;block_pc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pc&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;element_pc&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nb"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element_pc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Calculate how full this block needs to be:
&lt;/span&gt;        &lt;span class="n"&gt;block_fill_pc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;element_pc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;block_pc&lt;/span&gt;
        &lt;span class="c1"&gt;# Add an appropriate character to the render:
&lt;/span&gt;        &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;make_char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block_fill_pc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;"""
    Gets a character that represents "pc" percent (0.0 - 1.0).
    """&lt;/span&gt;
    &lt;span class="n"&gt;FULL_BLOCK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0x2588&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EMPTY&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;pc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nb"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FULL_BLOCK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, say I want to draw a bar of length &lt;strong&gt;3&lt;/strong&gt; and percentage &lt;strong&gt;0.7&lt;/strong&gt;. Inside &lt;code&gt;make_bar()&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;render&lt;/code&gt; is set to a list of 3 spaces.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;element_pc&lt;/code&gt; is set to &lt;strong&gt;0.33&lt;/strong&gt;, since each element in the list represents &lt;strong&gt;33%&lt;/strong&gt; of the bar area.&lt;/li&gt;
&lt;li&gt;In iteration &lt;code&gt;index = 0&lt;/code&gt;:

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;block_pc&lt;/code&gt; is set to the amount of the bar to be described by the first block. The calculation for this is &lt;code&gt;(the full bar percentage - the percentage already rendered by previous indexes).min(the maximum percentage that each block can represent)&lt;/code&gt;. That &lt;code&gt;.min(...)&lt;/code&gt; prevents us from biting off more than we can chew; each block can describe only as much as its maximum, and any remainder needs to be described by subsequent blocks. So, &lt;code&gt;block_pc&lt;/code&gt; is set to &lt;code&gt;(0.7 - (0 * 0.33)).min(0.33)&lt;/code&gt;, or &lt;strong&gt;0.33&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;block_fill_pc&lt;/code&gt; is set to the percentage full-ness of this block. Each block represents &lt;strong&gt;0.33&lt;/strong&gt; of the area and &lt;code&gt;block_pc&lt;/code&gt; is &lt;strong&gt;0.33&lt;/strong&gt;, so this block needs to be &lt;strong&gt;1.0&lt;/strong&gt; (100%) full.&lt;/li&gt;
&lt;li&gt;We pass that &lt;strong&gt;1.0&lt;/strong&gt; to &lt;code&gt;make_char()&lt;/code&gt; and -- since &lt;code&gt;1.0 &amp;gt; 0.5&lt;/code&gt; -- we get a Unicode full block back.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;In iteration &lt;code&gt;index = 1&lt;/code&gt;:

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;block_pc&lt;/code&gt; is set to the amount of the bar to be described by the second block: &lt;code&gt;(0.7 - (1 * 0.33)).min(0.33)&lt;/code&gt;, or &lt;strong&gt;0.33&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;block_fill_pc&lt;/code&gt; is set to the percentage full-ness of this block. Each block represents &lt;strong&gt;0.33&lt;/strong&gt; of the area and &lt;code&gt;block_pc&lt;/code&gt; is &lt;strong&gt;0.33&lt;/strong&gt;, so this block needs to be &lt;strong&gt;1.0&lt;/strong&gt; full.&lt;/li&gt;
&lt;li&gt;We pass that &lt;strong&gt;1.0&lt;/strong&gt; to &lt;code&gt;make_char()&lt;/code&gt; and -- since &lt;code&gt;1.0 &amp;gt; 0.5&lt;/code&gt; -- we get a Unicode full block back.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;In iteration &lt;code&gt;index = 2&lt;/code&gt;:

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;block_pc&lt;/code&gt; is set to the amount of the bar to be described by the third block: &lt;code&gt;(0.7 - (2 * 0.33)).min(0.33)&lt;/code&gt;, or &lt;strong&gt;0.04&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;block_fill_pc&lt;/code&gt; is set to the percentage full-ness of this block. Each block represents &lt;strong&gt;0.33&lt;/strong&gt; of the area and &lt;code&gt;block_pc&lt;/code&gt; is &lt;strong&gt;0.04&lt;/strong&gt;, so this block needs to be &lt;strong&gt;0.12&lt;/strong&gt; full.&lt;/li&gt;
&lt;li&gt;We pass that &lt;strong&gt;0.12&lt;/strong&gt; to &lt;code&gt;make_char()&lt;/code&gt; and -- since &lt;code&gt;0.12 &amp;lt; 0.5&lt;/code&gt; -- we get an empty space back.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Finally, we join &lt;code&gt;render&lt;/code&gt; together to get the bar as a string containing two Unicode full blocks and an empty string.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can run this for a number of rows of ever-increasing percentages with code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;"""
    Print a series of rows with ever-increasing percentages.
    """&lt;/span&gt;
    &lt;span class="n"&gt;ROW_COUNT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;
    &lt;span class="n"&gt;iteration_pc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ROW_COUNT&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ROW_COUNT&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;pc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iteration_pc&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;
        &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;make_bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: [&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;]"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here's our beautiful output!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.00: [      ]
0.10: [█     ]
0.20: [█     ]
0.30: [██    ]
0.40: [██    ]
0.50: [███   ]
0.60: [████  ]
0.70: [████  ]
0.80: [█████ ]
0.90: [█████ ]
1.00: [██████]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Well, not THAT beautiful
&lt;/h2&gt;

&lt;p&gt;It's &lt;em&gt;fine&lt;/em&gt;, but it's not &lt;em&gt;beautiful&lt;/em&gt;. According to those bars, &lt;strong&gt;0.10&lt;/strong&gt; and &lt;strong&gt;0.20&lt;/strong&gt; are the same, as are &lt;strong&gt;0.30&lt;/strong&gt; and &lt;strong&gt;0.40&lt;/strong&gt;, &lt;strong&gt;0.60&lt;/strong&gt; and &lt;strong&gt;0.70&lt;/strong&gt;, and &lt;strong&gt;0.80&lt;/strong&gt; and &lt;strong&gt;0.90&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Wouldn't it be nice to add some more granularity?&lt;/p&gt;

&lt;p&gt;Wouldn't be nice if we could draw blocks that were less than a full character width across?&lt;/p&gt;

&lt;p&gt;Well, we can!&lt;/p&gt;

&lt;p&gt;While the Unicode character &lt;code&gt;0x2588&lt;/code&gt; represents a full block, there's also a series of Unicode characters that describe &lt;em&gt;eighths&lt;/em&gt; of a block:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hex&lt;/th&gt;
&lt;th&gt;String&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x2588&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;█&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Left 8/8 (full block)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x2589&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;▉&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Left 7/8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x258A&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;▊&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Left 6/8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x258B&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;▋&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Left 5/8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x258C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;▌&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Left 4/8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x258D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;▍&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Left 3/8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x258E&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;▎&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Left 2/8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x258F&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;▏&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Left 1/8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Make it beautiful!
&lt;/h2&gt;

&lt;p&gt;So, let's update &lt;code&gt;make_char()&lt;/code&gt; to return one of these characters instead of a binary "on or off" for each block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;math&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ceil&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;"""
    Gets a character that represents "pc" percent (0.0 - 1.0).
    """&lt;/span&gt;
    &lt;span class="n"&gt;eighths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pc&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x2590&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;eighths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eighths&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;EMPTY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Essentially, we can calculate how many eighths a percentage is by multiplying it by 8:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;0.000&lt;/strong&gt; (&lt;code&gt;0.000 * 8&lt;/code&gt;) is &lt;strong&gt;0&lt;/strong&gt; eighths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0.125&lt;/strong&gt; (&lt;code&gt;0.125 * 8&lt;/code&gt;) is &lt;strong&gt;1&lt;/strong&gt; eighth.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0.250&lt;/strong&gt; (&lt;code&gt;0.250 * 8&lt;/code&gt;) is &lt;strong&gt;2&lt;/strong&gt; eighths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0.375&lt;/strong&gt; (&lt;code&gt;0.375 * 8&lt;/code&gt;) is &lt;strong&gt;3&lt;/strong&gt; eighths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0.500&lt;/strong&gt; (&lt;code&gt;0.500 * 8&lt;/code&gt;) is &lt;strong&gt;4&lt;/strong&gt; eighths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0.625&lt;/strong&gt; (&lt;code&gt;0.625 * 8&lt;/code&gt;) is &lt;strong&gt;5&lt;/strong&gt; eighths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0.750&lt;/strong&gt; (&lt;code&gt;0.750 * 8&lt;/code&gt;) is &lt;strong&gt;6&lt;/strong&gt; eighths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;0.875&lt;/strong&gt; (&lt;code&gt;0.875 * 8&lt;/code&gt;) is &lt;strong&gt;7&lt;/strong&gt; eighths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1.000&lt;/strong&gt; (&lt;code&gt;1.000 * 8&lt;/code&gt;) is &lt;strong&gt;8&lt;/strong&gt; eighths.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When we know how many eighths a percentage is, we can subtract that &lt;em&gt;offset&lt;/em&gt; from &lt;code&gt;0x2590&lt;/code&gt; to get the correct symbol:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;0x2590 - 1 = 0x258F&lt;/code&gt; (1/8)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0x2590 - 2 = 0x258E&lt;/code&gt; (2/8)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0x2590 - 3 = 0x258D&lt;/code&gt; (3/8)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0x2590 - 4 = 0x258C&lt;/code&gt; (4/8)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0x2590 - 5 = 0x258B&lt;/code&gt; (5/8)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0x2590 - 6 = 0x258A&lt;/code&gt; (6/8)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0x2590 - 7 = 0x2589&lt;/code&gt; (7/8)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0x2590 - 8 = 0x2588&lt;/code&gt; (8/8)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now if we run the code with the updated &lt;code&gt;make_char()&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.00: [      ]
0.10: [▋     ]
0.20: [█▎    ]
0.30: [█▉    ]
0.40: [██▌   ]
0.50: [███   ]
0.60: [███▋  ]
0.70: [████▎ ]
0.80: [████▉ ]
0.90: [█████▌]
1.00: [██████]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ta-da! Every row now has a &lt;em&gt;much&lt;/em&gt; more accurate bar!&lt;/p&gt;

&lt;p&gt;In fact, with one quick change to the script, we can create a row for every possible partial block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"__main__"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="s"&gt;"""
    Print a series of rows with ever-increasing percentages.
    """&lt;/span&gt;
    &lt;span class="n"&gt;LENGTH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
    &lt;span class="n"&gt;ROW_COUNT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;LENGTH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;iteration_pc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Decimal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ROW_COUNT&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ROW_COUNT&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;pc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;iteration_pc&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;
        &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;make_bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;LENGTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: [&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;]"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0.00: [  ]
0.06: [▏ ]
0.12: [▎ ]
0.19: [▍ ]
0.25: [▌ ]
0.31: [▋ ]
0.38: [▊ ]
0.44: [▉ ]
0.50: [█ ]
0.56: [█▏]
0.62: [█▎]
0.69: [█▍]
0.75: [█▌]
0.81: [█▋]
0.88: [█▊]
0.94: [█▉]
1.00: [██]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, who said command-line tools can't be beautiful?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Featured photo by &lt;a href="https://unsplash.com/@wesleyphotography?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Wesley Tingey&lt;/a&gt; on &lt;a href="https://unsplash.com/?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>firstpost</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
