How to Create a Lipstick Chart With Matplotlib

Today, I will show you how to create a lipstick chart for visualizing progress on metrics where the lower the value, the better.

I’ve prepared a simple dataset about mortality and diseases, so that you can focus on creating the visualization.

The data comes from the World Bank, and if you want to learn more, I’ve written about the visualization in my new free newsletter Data Wonder.

Let’s get started.


Step 1 – Importing libraries

The first and simplest part is to import the required libraries like pandas and matplotlib.

<span>import</span> <span>numpy</span> <span>as</span> <span>np</span>
<span>import</span> <span>pandas</span> <span>as</span> <span>pd</span>
<span>import</span> <span>seaborn</span> <span>as</span> <span>sns</span>
<span>import</span> <span>matplotlib.pyplot</span> <span>as</span> <span>plt</span>
<span>from</span> <span>PIL</span> <span>import</span> <span>Image</span>
<span>from</span> <span>matplotlib.lines</span> <span>import</span> <span>Line2D</span>
<span>import</span> <span>numpy</span> <span>as</span> <span>np</span>
<span>import</span> <span>pandas</span> <span>as</span> <span>pd</span>

<span>import</span> <span>seaborn</span> <span>as</span> <span>sns</span>
<span>import</span> <span>matplotlib.pyplot</span> <span>as</span> <span>plt</span>

<span>from</span> <span>PIL</span> <span>import</span> <span>Image</span>
<span>from</span> <span>matplotlib.lines</span> <span>import</span> <span>Line2D</span>
import numpy as np import pandas as pd import seaborn as sns import matplotlib.pyplot as plt from PIL import Image from matplotlib.lines import Line2D

Enter fullscreen mode Exit fullscreen mode

Congratulation, you just completed step 1! 🥳


Step 2 – Create a Seaborn style

Next, I want to create a color-scheme and select a font. Sites like Coolors and Colorhunt are great resources when searching for beautiful colors.

Here’s my code and settings to create the seaborn style for this tutorial.

<span>FONT_FAMILY</span> <span>=</span> <span>"</span><span>serif</span><span>"</span>
<span>BACKGROUND_COLOR</span> <span>=</span> <span>"</span><span>#FAE8E0</span><span>"</span>
<span>TEXT_COLOR</span> <span>=</span> <span>"</span><span>#33261D</span><span>"</span>
<span>BAR_COLOR</span> <span>=</span> <span>"</span><span>#EF7C8E</span><span>"</span>
<span>sns</span><span>.</span><span>set_style</span><span>({</span>
<span>"</span><span>axes.facecolor</span><span>"</span><span>:</span> <span>BACKGROUND_COLOR</span><span>,</span>
<span>"</span><span>figure.facecolor</span><span>"</span><span>:</span> <span>BACKGROUND_COLOR</span><span>,</span>
<span>"</span><span>text.color</span><span>"</span><span>:</span> <span>TEXT_COLOR</span><span>,</span>
<span>"</span><span>font.family</span><span>"</span><span>:</span> <span>FONT_FAMILY</span><span>,</span>
<span>"</span><span>xtick.bottom</span><span>"</span><span>:</span> <span>False</span><span>,</span>
<span>"</span><span>xtick.top</span><span>"</span><span>:</span> <span>False</span><span>,</span>
<span>"</span><span>ytick.left</span><span>"</span><span>:</span> <span>False</span><span>,</span>
<span>"</span><span>ytick.right</span><span>"</span><span>:</span> <span>False</span><span>,</span>
<span>"</span><span>axes.spines.left</span><span>"</span><span>:</span> <span>False</span><span>,</span>
<span>"</span><span>axes.spines.bottom</span><span>"</span><span>:</span> <span>False</span><span>,</span>
<span>"</span><span>axes.spines.right</span><span>"</span><span>:</span> <span>False</span><span>,</span>
<span>"</span><span>axes.spines.top</span><span>"</span><span>:</span> <span>False</span><span>,</span>
<span>})</span>
<span>FONT_FAMILY</span> <span>=</span> <span>"</span><span>serif</span><span>"</span>
<span>BACKGROUND_COLOR</span> <span>=</span> <span>"</span><span>#FAE8E0</span><span>"</span>
<span>TEXT_COLOR</span> <span>=</span> <span>"</span><span>#33261D</span><span>"</span>
<span>BAR_COLOR</span> <span>=</span> <span>"</span><span>#EF7C8E</span><span>"</span>

<span>sns</span><span>.</span><span>set_style</span><span>({</span>
    <span>"</span><span>axes.facecolor</span><span>"</span><span>:</span> <span>BACKGROUND_COLOR</span><span>,</span>
    <span>"</span><span>figure.facecolor</span><span>"</span><span>:</span> <span>BACKGROUND_COLOR</span><span>,</span>

    <span>"</span><span>text.color</span><span>"</span><span>:</span> <span>TEXT_COLOR</span><span>,</span>
    <span>"</span><span>font.family</span><span>"</span><span>:</span> <span>FONT_FAMILY</span><span>,</span>

    <span>"</span><span>xtick.bottom</span><span>"</span><span>:</span> <span>False</span><span>,</span>
    <span>"</span><span>xtick.top</span><span>"</span><span>:</span> <span>False</span><span>,</span>
    <span>"</span><span>ytick.left</span><span>"</span><span>:</span> <span>False</span><span>,</span>
    <span>"</span><span>ytick.right</span><span>"</span><span>:</span> <span>False</span><span>,</span>

    <span>"</span><span>axes.spines.left</span><span>"</span><span>:</span> <span>False</span><span>,</span>
    <span>"</span><span>axes.spines.bottom</span><span>"</span><span>:</span> <span>False</span><span>,</span>
    <span>"</span><span>axes.spines.right</span><span>"</span><span>:</span> <span>False</span><span>,</span>
    <span>"</span><span>axes.spines.top</span><span>"</span><span>:</span> <span>False</span><span>,</span>
<span>})</span>
FONT_FAMILY = "serif" BACKGROUND_COLOR = "#FAE8E0" TEXT_COLOR = "#33261D" BAR_COLOR = "#EF7C8E" sns.set_style({ "axes.facecolor": BACKGROUND_COLOR, "figure.facecolor": BACKGROUND_COLOR, "text.color": TEXT_COLOR, "font.family": FONT_FAMILY, "xtick.bottom": False, "xtick.top": False, "ytick.left": False, "ytick.right": False, "axes.spines.left": False, "axes.spines.bottom": False, "axes.spines.right": False, "axes.spines.top": False, })

Enter fullscreen mode Exit fullscreen mode

I’m removing all the ticks and lines to create a clean visualization, and the grids don’t add any valuable information to our lipstick chart.


Step 3 – Reading the data

You can read the CSV directly from the url as I do in the code below.

<span>df</span> <span>=</span> <span>pd</span><span>.</span><span>read_csv</span><span>(</span>
<span>"</span><span>https://raw.githubusercontent.com/oscarleoo/matplotlib-tutorial-data/main/mortality-and-decease.csv</span><span>"</span>
<span>)</span>
<span>df</span> <span>=</span> <span>pd</span><span>.</span><span>read_csv</span><span>(</span>
    <span>"</span><span>https://raw.githubusercontent.com/oscarleoo/matplotlib-tutorial-data/main/mortality-and-decease.csv</span><span>"</span>
<span>)</span>
df = pd.read_csv( "https://raw.githubusercontent.com/oscarleoo/matplotlib-tutorial-data/main/mortality-and-decease.csv" )

Enter fullscreen mode Exit fullscreen mode

Here’s what the dataframe looks like.

Most values are self-explanatory except for per, which shows each row’s scale. For example, the latest “Maternal mortality” value was 223 out of 100,000 births.


Step 4 – Adding bars

Now it’s time to add some data.

I’m adding bars for both 2000 and the latest values. Since my goal is to show the relative decrease for each value, I’m dividing each row by its 2000 value.

That means each bar for 2000 will reach 1, so it’s only a visual helper and doesn’t add any additional information.

Here’s my function to add bars.

<span>def</span> <span>add_bars</span><span>(</span><span>ax</span><span>,</span> <span>x</span><span>,</span> <span>width</span><span>,</span> <span>alpha</span><span>,</span> <span>label</span><span>):</span>
<span>sns</span><span>.</span><span>barplot</span><span>(</span>
<span>ax</span><span>=</span><span>ax</span><span>,</span> <span>x</span><span>=</span><span>x</span><span>,</span> <span>y</span><span>=</span><span>[</span><span>i</span> <span>for</span> <span>i</span> <span>in</span> <span>range</span><span>(</span><span>len</span><span>(</span><span>x</span><span>))],</span> <span>label</span><span>=</span><span>label</span><span>,</span>
<span>width</span><span>=</span><span>width</span><span>,</span> <span>alpha</span><span>=</span><span>alpha</span><span>,</span>
<span>color</span><span>=</span><span>BAR_COLOR</span><span>,</span>
<span>edgecolor</span><span>=</span><span>TEXT_COLOR</span><span>,</span>
<span>orient</span><span>=</span><span>"</span><span>h</span><span>"</span>
<span>)</span>
<span>def</span> <span>add_bars</span><span>(</span><span>ax</span><span>,</span> <span>x</span><span>,</span> <span>width</span><span>,</span> <span>alpha</span><span>,</span> <span>label</span><span>):</span>
    <span>sns</span><span>.</span><span>barplot</span><span>(</span>
        <span>ax</span><span>=</span><span>ax</span><span>,</span> <span>x</span><span>=</span><span>x</span><span>,</span> <span>y</span><span>=</span><span>[</span><span>i</span> <span>for</span> <span>i</span> <span>in</span> <span>range</span><span>(</span><span>len</span><span>(</span><span>x</span><span>))],</span> <span>label</span><span>=</span><span>label</span><span>,</span>
        <span>width</span><span>=</span><span>width</span><span>,</span> <span>alpha</span><span>=</span><span>alpha</span><span>,</span>
        <span>color</span><span>=</span><span>BAR_COLOR</span><span>,</span>
        <span>edgecolor</span><span>=</span><span>TEXT_COLOR</span><span>,</span>
        <span>orient</span><span>=</span><span>"</span><span>h</span><span>"</span>
    <span>)</span>
def add_bars(ax, x, width, alpha, label): sns.barplot( ax=ax, x=x, y=[i for i in range(len(x))], label=label, width=width, alpha=alpha, color=BAR_COLOR, edgecolor=TEXT_COLOR, orient="h" )

Enter fullscreen mode Exit fullscreen mode

I create a figure and run the add_bars() function like this.

<span>fig</span><span>,</span> <span>ax</span> <span>=</span> <span>plt</span><span>.</span><span>subplots</span><span>(</span><span>nrows</span><span>=</span><span>1</span><span>,</span> <span>ncols</span><span>=</span><span>1</span><span>,</span> <span>figsize</span><span>=</span><span>(</span><span>18</span><span>,</span> <span>2.7</span> <span>*</span> <span>len</span><span>(</span><span>df</span><span>)))</span>
<span>add_bars</span><span>(</span>
<span>ax</span><span>=</span><span>ax</span><span>,</span> <span>x</span><span>=</span><span>df</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>]</span> <span>/</span> <span>df</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>],</span>
<span>width</span><span>=</span><span>0.55</span><span>,</span> <span>alpha</span><span>=</span><span>0.2</span><span>,</span> <span>label</span><span>=</span><span>"</span><span>2000</span><span>"</span>
<span>)</span>
<span>add_bars</span><span>(</span>
<span>ax</span><span>=</span><span>ax</span><span>,</span> <span>x</span><span>=</span><span>df</span><span>[</span><span>"</span><span>latest_value</span><span>"</span><span>]</span> <span>/</span> <span>df</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>],</span>
<span>width</span><span>=</span><span>0.7</span><span>,</span> <span>alpha</span><span>=</span><span>1</span><span>,</span> <span>label</span><span>=</span><span>"</span><span>Latest</span><span>"</span>
<span>)</span>
<span>fig</span><span>,</span> <span>ax</span> <span>=</span> <span>plt</span><span>.</span><span>subplots</span><span>(</span><span>nrows</span><span>=</span><span>1</span><span>,</span> <span>ncols</span><span>=</span><span>1</span><span>,</span> <span>figsize</span><span>=</span><span>(</span><span>18</span><span>,</span> <span>2.7</span> <span>*</span> <span>len</span><span>(</span><span>df</span><span>)))</span>

<span>add_bars</span><span>(</span>
    <span>ax</span><span>=</span><span>ax</span><span>,</span> <span>x</span><span>=</span><span>df</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>]</span> <span>/</span> <span>df</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>],</span>
    <span>width</span><span>=</span><span>0.55</span><span>,</span> <span>alpha</span><span>=</span><span>0.2</span><span>,</span> <span>label</span><span>=</span><span>"</span><span>2000</span><span>"</span>
<span>)</span>

<span>add_bars</span><span>(</span>
    <span>ax</span><span>=</span><span>ax</span><span>,</span> <span>x</span><span>=</span><span>df</span><span>[</span><span>"</span><span>latest_value</span><span>"</span><span>]</span> <span>/</span> <span>df</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>],</span>
    <span>width</span><span>=</span><span>0.7</span><span>,</span> <span>alpha</span><span>=</span><span>1</span><span>,</span> <span>label</span><span>=</span><span>"</span><span>Latest</span><span>"</span>
<span>)</span>
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 2.7 * len(df))) add_bars( ax=ax, x=df["2000"] / df["2000"], width=0.55, alpha=0.2, label="2000" ) add_bars( ax=ax, x=df["latest_value"] / df["2000"], width=0.7, alpha=1, label="Latest" )

Enter fullscreen mode Exit fullscreen mode

The result for the code we have so far looks like this.

Let’s continue.


Step 5 – Formatting the axes

The names for each row are to long to use without line-breaks. That’s why I created the following function to add \n to the strings in a few places.

<span>def</span> <span>split_name</span><span>(</span><span>name</span><span>,</span> <span>limit</span><span>=</span><span>20</span><span>):</span>
<span>split</span> <span>=</span> <span>name</span><span>.</span><span>split</span><span>()</span>
<span>s</span> <span>=</span> <span>""</span>
<span>for</span> <span>s_</span> <span>in</span> <span>split</span><span>:</span>
<span>if</span> <span>len</span><span>(</span><span>s</span><span>.</span><span>split</span><span>(</span><span>"</span><span>\n</span><span>"</span><span>)[</span><span>-</span><span>1</span><span>]</span> <span>+</span> <span>s_</span><span>)</span> <span>></span> <span>limit</span><span>:</span>
<span>s</span> <span>+=</span> <span>"</span><span>\n</span><span>"</span> <span>+</span> <span>s_</span>
<span>else</span><span>:</span>
<span>s</span> <span>+=</span> <span>"</span><span> </span><span>"</span> <span>+</span> <span>s_</span>
<span>return</span> <span>s</span><span>.</span><span>strip</span><span>()</span>
<span>def</span> <span>split_name</span><span>(</span><span>name</span><span>,</span> <span>limit</span><span>=</span><span>20</span><span>):</span>
    <span>split</span> <span>=</span> <span>name</span><span>.</span><span>split</span><span>()</span>
    <span>s</span> <span>=</span> <span>""</span>

    <span>for</span> <span>s_</span> <span>in</span> <span>split</span><span>:</span>
        <span>if</span> <span>len</span><span>(</span><span>s</span><span>.</span><span>split</span><span>(</span><span>"</span><span>\n</span><span>"</span><span>)[</span><span>-</span><span>1</span><span>]</span> <span>+</span> <span>s_</span><span>)</span> <span>></span> <span>limit</span><span>:</span>
            <span>s</span> <span>+=</span> <span>"</span><span>\n</span><span>"</span> <span>+</span> <span>s_</span>
        <span>else</span><span>:</span>
            <span>s</span> <span>+=</span> <span>"</span><span> </span><span>"</span> <span>+</span> <span>s_</span>

    <span>return</span> <span>s</span><span>.</span><span>strip</span><span>()</span>
def split_name(name, limit=20): split = name.split() s = "" for s_ in split: if len(s.split("\n")[-1] + s_) > limit: s += "\n" + s_ else: s += " " + s_ return s.strip()

Enter fullscreen mode Exit fullscreen mode

I also want increase the fontsize and remove unnecessary information to make the chart readable. The code to create the visualization now looks like this.

<span>fig</span><span>,</span> <span>ax</span> <span>=</span> <span>plt</span><span>.</span><span>subplots</span><span>(</span><span>nrows</span><span>=</span><span>1</span><span>,</span> <span>ncols</span><span>=</span><span>1</span><span>,</span> <span>figsize</span><span>=</span><span>(</span><span>18</span><span>,</span> <span>2.7</span> <span>*</span> <span>len</span><span>(</span><span>df</span><span>)))</span>
<span>...</span>
<span>ax</span><span>.</span><span>set</span><span>(</span><span>xlabel</span><span>=</span><span>None</span><span>,</span> <span>ylabel</span><span>=</span><span>None</span><span>,</span> <span>xticks</span><span>=</span><span>[])</span>
<span>ax</span><span>.</span><span>tick_params</span><span>(</span><span>"</span><span>y</span><span>"</span><span>,</span> <span>labelsize</span><span>=</span><span>28</span><span>,</span> <span>pad</span><span>=</span><span>32</span><span>)</span>
<span>ax</span><span>.</span><span>tick_params</span><span>(</span><span>"</span><span>x</span><span>"</span><span>,</span> <span>labelsize</span><span>=</span><span>20</span><span>,</span> <span>pad</span><span>=</span><span>16</span><span>)</span>
<span>ax</span><span>.</span><span>set_yticks</span><span>(</span>
<span>ticks</span><span>=</span><span>[</span><span>i</span> <span>for</span> <span>i</span> <span>in</span> <span>range</span><span>(</span><span>len</span><span>(</span><span>df</span><span>))],</span>
<span>labels</span><span>=</span><span>[</span><span>split_name</span><span>(</span><span>n</span><span>,</span> <span>limit</span><span>=</span><span>19</span><span>)</span> <span>for</span> <span>n</span> <span>in</span> <span>df</span><span>[</span><span>"</span><span>indicator_name</span><span>"</span><span>]],</span>
<span>linespacing</span><span>=</span><span>1.7</span><span>,</span> <span>va</span><span>=</span><span>"</span><span>center</span><span>"</span>
<span>)</span>
<span>fig</span><span>,</span> <span>ax</span> <span>=</span> <span>plt</span><span>.</span><span>subplots</span><span>(</span><span>nrows</span><span>=</span><span>1</span><span>,</span> <span>ncols</span><span>=</span><span>1</span><span>,</span> <span>figsize</span><span>=</span><span>(</span><span>18</span><span>,</span> <span>2.7</span> <span>*</span> <span>len</span><span>(</span><span>df</span><span>)))</span>
<span>...</span>

<span>ax</span><span>.</span><span>set</span><span>(</span><span>xlabel</span><span>=</span><span>None</span><span>,</span> <span>ylabel</span><span>=</span><span>None</span><span>,</span> <span>xticks</span><span>=</span><span>[])</span>
<span>ax</span><span>.</span><span>tick_params</span><span>(</span><span>"</span><span>y</span><span>"</span><span>,</span> <span>labelsize</span><span>=</span><span>28</span><span>,</span> <span>pad</span><span>=</span><span>32</span><span>)</span>
<span>ax</span><span>.</span><span>tick_params</span><span>(</span><span>"</span><span>x</span><span>"</span><span>,</span> <span>labelsize</span><span>=</span><span>20</span><span>,</span> <span>pad</span><span>=</span><span>16</span><span>)</span>

<span>ax</span><span>.</span><span>set_yticks</span><span>(</span>
    <span>ticks</span><span>=</span><span>[</span><span>i</span> <span>for</span> <span>i</span> <span>in</span> <span>range</span><span>(</span><span>len</span><span>(</span><span>df</span><span>))],</span>
    <span>labels</span><span>=</span><span>[</span><span>split_name</span><span>(</span><span>n</span><span>,</span> <span>limit</span><span>=</span><span>19</span><span>)</span> <span>for</span> <span>n</span> <span>in</span> <span>df</span><span>[</span><span>"</span><span>indicator_name</span><span>"</span><span>]],</span>
    <span>linespacing</span><span>=</span><span>1.7</span><span>,</span> <span>va</span><span>=</span><span>"</span><span>center</span><span>"</span>
<span>)</span>
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 2.7 * len(df))) ... ax.set(xlabel=None, ylabel=None, xticks=[]) ax.tick_params("y", labelsize=28, pad=32) ax.tick_params("x", labelsize=20, pad=16) ax.set_yticks( ticks=[i for i in range(len(df))], labels=[split_name(n, limit=19) for n in df["indicator_name"]], linespacing=1.7, va="center" )

Enter fullscreen mode Exit fullscreen mode

Here’s the updated results.

Let’s add some additional information.


Step 5 – Adding useful information

You always want to make sure that the users understand what they are looking at. Right now, we have no such information.

For starters, I want to add the current values, which I do with the following function.

<span>def</span> <span>add_info_text</span><span>(</span><span>ax</span><span>,</span> <span>row</span><span>,</span> <span>index</span><span>):</span>
<span>value</span> <span>=</span> <span>round</span><span>(</span><span>row</span><span>[</span><span>"</span><span>latest_value</span><span>"</span><span>],</span> <span>1</span><span>)</span>
<span>per</span> <span>=</span> <span>row</span><span>[</span><span>"</span><span>per</span><span>"</span><span>]</span>
<span>year</span> <span>=</span> <span>row</span><span>[</span><span>"</span><span>latest_year</span><span>"</span><span>]</span>
<span>text</span> <span>=</span> <span>"</span><span>{:,} out of</span><span>\n</span><span>{:,} ({})</span><span>"</span><span>.</span><span>format</span><span>(</span><span>value</span><span>,</span> <span>per</span><span>,</span> <span>year</span><span>)</span>
<span>ax</span><span>.</span><span>annotate</span><span>(</span>
<span>text</span><span>=</span><span>text</span><span>,</span>
<span>xy</span><span>=</span><span>(</span><span>0.02</span><span>,</span> <span>index</span><span>),</span>
<span>color</span><span>=</span><span>"</span><span>#fff</span><span>"</span><span>,</span>
<span>fontsize</span><span>=</span><span>24</span><span>,</span>
<span>va</span><span>=</span><span>"</span><span>center</span><span>"</span><span>,</span>
<span>linespacing</span><span>=</span><span>1.7</span>
<span>)</span>
<span>def</span> <span>add_info_text</span><span>(</span><span>ax</span><span>,</span> <span>row</span><span>,</span> <span>index</span><span>):</span>
    <span>value</span> <span>=</span> <span>round</span><span>(</span><span>row</span><span>[</span><span>"</span><span>latest_value</span><span>"</span><span>],</span> <span>1</span><span>)</span>
    <span>per</span> <span>=</span> <span>row</span><span>[</span><span>"</span><span>per</span><span>"</span><span>]</span>
    <span>year</span> <span>=</span> <span>row</span><span>[</span><span>"</span><span>latest_year</span><span>"</span><span>]</span>
    <span>text</span> <span>=</span> <span>"</span><span>{:,} out of</span><span>\n</span><span>{:,} ({})</span><span>"</span><span>.</span><span>format</span><span>(</span><span>value</span><span>,</span> <span>per</span><span>,</span> <span>year</span><span>)</span>

    <span>ax</span><span>.</span><span>annotate</span><span>(</span>
        <span>text</span><span>=</span><span>text</span><span>,</span> 
        <span>xy</span><span>=</span><span>(</span><span>0.02</span><span>,</span> <span>index</span><span>),</span> 
        <span>color</span><span>=</span><span>"</span><span>#fff</span><span>"</span><span>,</span> 
        <span>fontsize</span><span>=</span><span>24</span><span>,</span>
        <span>va</span><span>=</span><span>"</span><span>center</span><span>"</span><span>,</span> 
        <span>linespacing</span><span>=</span><span>1.7</span>
    <span>)</span>
def add_info_text(ax, row, index): value = round(row["latest_value"], 1) per = row["per"] year = row["latest_year"] text = "{:,} out of\n{:,} ({})".format(value, per, year) ax.annotate( text=text, xy=(0.02, index), color="#fff", fontsize=24, va="center", linespacing=1.7 )

Enter fullscreen mode Exit fullscreen mode

And since the purpose is to show the relative decrease of each metric compared to its value from 2000, I have another function showing the change for each row.

<span>def</span> <span>add_change_text</span><span>(</span><span>ax</span><span>,</span> <span>row</span><span>,</span> <span>index</span><span>):</span>
<span>change</span> <span>=</span> <span>round</span><span>(</span><span>100</span> <span>*</span> <span>row</span><span>[</span><span>"</span><span>change</span><span>"</span><span>],</span> <span>1</span><span>)</span>
<span>text</span> <span>=</span> <span>"</span><span>{:,}%</span><span>"</span><span>.</span><span>format</span><span>(</span><span>change</span><span>)</span>
<span>x</span> <span>=</span> <span>row</span><span>[</span><span>"</span><span>latest_value</span><span>"</span><span>]</span> <span>/</span> <span>row</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>]</span> <span>+</span> <span>0.02</span>
<span>ax</span><span>.</span><span>annotate</span><span>(</span>
<span>text</span><span>=</span><span>"</span><span>{:,}%</span><span>"</span><span>.</span><span>format</span><span>(</span><span>change</span><span>),</span> <span>xy</span><span>=</span><span>(</span><span>x</span><span>,</span> <span>index</span><span>),</span> <span>fontsize</span><span>=</span><span>22</span><span>,</span>
<span>va</span><span>=</span><span>"</span><span>center</span><span>"</span><span>,</span> <span>linespacing</span><span>=</span><span>1.7</span>
<span>)</span>
<span>def</span> <span>add_change_text</span><span>(</span><span>ax</span><span>,</span> <span>row</span><span>,</span> <span>index</span><span>):</span>
    <span>change</span> <span>=</span> <span>round</span><span>(</span><span>100</span> <span>*</span> <span>row</span><span>[</span><span>"</span><span>change</span><span>"</span><span>],</span> <span>1</span><span>)</span>
    <span>text</span> <span>=</span> <span>"</span><span>{:,}%</span><span>"</span><span>.</span><span>format</span><span>(</span><span>change</span><span>)</span>
    <span>x</span> <span>=</span> <span>row</span><span>[</span><span>"</span><span>latest_value</span><span>"</span><span>]</span> <span>/</span> <span>row</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>]</span> <span>+</span> <span>0.02</span>

    <span>ax</span><span>.</span><span>annotate</span><span>(</span>
        <span>text</span><span>=</span><span>"</span><span>{:,}%</span><span>"</span><span>.</span><span>format</span><span>(</span><span>change</span><span>),</span> <span>xy</span><span>=</span><span>(</span><span>x</span><span>,</span> <span>index</span><span>),</span> <span>fontsize</span><span>=</span><span>22</span><span>,</span>
        <span>va</span><span>=</span><span>"</span><span>center</span><span>"</span><span>,</span>  <span>linespacing</span><span>=</span><span>1.7</span>
    <span>)</span>
def add_change_text(ax, row, index): change = round(100 * row["change"], 1) text = "{:,}%".format(change) x = row["latest_value"] / row["2000"] + 0.02 ax.annotate( text="{:,}%".format(change), xy=(x, index), fontsize=22, va="center", linespacing=1.7 )

Enter fullscreen mode Exit fullscreen mode

I add both functions under a for-loop.

<span>fig</span><span>,</span> <span>ax</span> <span>=</span> <span>plt</span><span>.</span><span>subplots</span><span>(</span><span>nrows</span><span>=</span><span>1</span><span>,</span> <span>ncols</span><span>=</span><span>1</span><span>,</span> <span>figsize</span><span>=</span><span>(</span><span>18</span><span>,</span> <span>2.7</span> <span>*</span> <span>len</span><span>(</span><span>df</span><span>)))</span>
<span>...</span>
<span>for</span> <span>index</span><span>,</span> <span>row</span> <span>in</span> <span>df</span><span>.</span><span>reset_index</span><span>().</span><span>iterrows</span><span>():</span>
<span>add_info_text</span><span>(</span><span>ax</span><span>,</span> <span>row</span><span>,</span> <span>index</span><span>)</span>
<span>add_change_text</span><span>(</span><span>ax</span><span>,</span> <span>row</span><span>,</span> <span>index</span><span>)</span>
<span>fig</span><span>,</span> <span>ax</span> <span>=</span> <span>plt</span><span>.</span><span>subplots</span><span>(</span><span>nrows</span><span>=</span><span>1</span><span>,</span> <span>ncols</span><span>=</span><span>1</span><span>,</span> <span>figsize</span><span>=</span><span>(</span><span>18</span><span>,</span> <span>2.7</span> <span>*</span> <span>len</span><span>(</span><span>df</span><span>)))</span>
<span>...</span>

<span>for</span> <span>index</span><span>,</span> <span>row</span> <span>in</span> <span>df</span><span>.</span><span>reset_index</span><span>().</span><span>iterrows</span><span>():</span>
    <span>add_info_text</span><span>(</span><span>ax</span><span>,</span> <span>row</span><span>,</span> <span>index</span><span>)</span>
    <span>add_change_text</span><span>(</span><span>ax</span><span>,</span> <span>row</span><span>,</span> <span>index</span><span>)</span>
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 2.7 * len(df))) ... for index, row in df.reset_index().iterrows(): add_info_text(ax, row, index) add_change_text(ax, row, index)

Enter fullscreen mode Exit fullscreen mode

Here’s the output.

It’s starting to look good.


Step 6 – Adding a title and legend

In this step, I’m simply using some built in Matplotlib functions to add a title and legend. Since we defined label in add_bars() much of the styling is automatic.

Apart from defining a title and legend, I’m also adding a border using Line2D for visual effect.

<span>fig</span><span>,</span> <span>ax</span> <span>=</span> <span>plt</span><span>.</span><span>subplots</span><span>(</span><span>nrows</span><span>=</span><span>1</span><span>,</span> <span>ncols</span><span>=</span><span>1</span><span>,</span> <span>figsize</span><span>=</span><span>(</span><span>18</span><span>,</span> <span>2.7</span> <span>*</span> <span>len</span><span>(</span><span>df</span><span>)))</span>
<span>...</span>
<span>line</span> <span>=</span> <span>Line2D</span><span>([</span><span>-</span><span>0.33</span><span>,</span> <span>1.0</span><span>],</span> <span>[</span><span>-</span><span>0.9</span><span>,</span> <span>-</span><span>0.9</span><span>],</span> <span>color</span><span>=</span><span>TEXT_COLOR</span><span>)</span>
<span>line</span><span>.</span><span>set_clip_on</span><span>(</span><span>False</span><span>)</span>
<span>ax</span><span>.</span><span>add_artist</span><span>(</span><span>line</span><span>)</span>
<span>title</span> <span>=</span> <span>"</span><span>Lipstick Chart - Relative</span><span>\n</span><span>Decreases Compared</span><span>\n</span><span>to 2000</span><span>"</span>
<span>plt</span><span>.</span><span>title</span><span>(</span><span>title</span><span>,</span> <span>x</span><span>=-</span><span>0.32</span><span>,</span> <span>y</span><span>=</span><span>1.11</span><span>,</span> <span>fontsize</span><span>=</span><span>58</span><span>,</span> <span>ha</span><span>=</span><span>"</span><span>left</span><span>"</span><span>,</span> <span>linespacing</span><span>=</span><span>1.6</span><span>)</span>
<span>plt</span><span>.</span><span>legend</span><span>(</span><span>bbox_to_anchor</span><span>=</span><span>(</span><span>0.75</span><span>,</span> <span>1.14</span><span>),</span> <span>loc</span><span>=</span><span>'</span><span>lower center</span><span>'</span><span>,</span> <span>borderaxespad</span><span>=</span><span>0</span><span>,</span> <span>ncol</span><span>=</span><span>1</span><span>,</span> <span>fontsize</span><span>=</span><span>44</span><span>,</span> <span>edgecolor</span><span>=</span><span>"</span><span>#FAE8E0</span><span>"</span><span>)</span>
<span>fig</span><span>,</span> <span>ax</span> <span>=</span> <span>plt</span><span>.</span><span>subplots</span><span>(</span><span>nrows</span><span>=</span><span>1</span><span>,</span> <span>ncols</span><span>=</span><span>1</span><span>,</span> <span>figsize</span><span>=</span><span>(</span><span>18</span><span>,</span> <span>2.7</span> <span>*</span> <span>len</span><span>(</span><span>df</span><span>)))</span>
<span>...</span>

<span>line</span> <span>=</span> <span>Line2D</span><span>([</span><span>-</span><span>0.33</span><span>,</span> <span>1.0</span><span>],</span> <span>[</span><span>-</span><span>0.9</span><span>,</span> <span>-</span><span>0.9</span><span>],</span> <span>color</span><span>=</span><span>TEXT_COLOR</span><span>)</span>
<span>line</span><span>.</span><span>set_clip_on</span><span>(</span><span>False</span><span>)</span>
<span>ax</span><span>.</span><span>add_artist</span><span>(</span><span>line</span><span>)</span>

<span>title</span> <span>=</span> <span>"</span><span>Lipstick Chart - Relative</span><span>\n</span><span>Decreases Compared</span><span>\n</span><span>to 2000</span><span>"</span>
<span>plt</span><span>.</span><span>title</span><span>(</span><span>title</span><span>,</span> <span>x</span><span>=-</span><span>0.32</span><span>,</span> <span>y</span><span>=</span><span>1.11</span><span>,</span> <span>fontsize</span><span>=</span><span>58</span><span>,</span> <span>ha</span><span>=</span><span>"</span><span>left</span><span>"</span><span>,</span> <span>linespacing</span><span>=</span><span>1.6</span><span>)</span>
<span>plt</span><span>.</span><span>legend</span><span>(</span><span>bbox_to_anchor</span><span>=</span><span>(</span><span>0.75</span><span>,</span> <span>1.14</span><span>),</span> <span>loc</span><span>=</span><span>'</span><span>lower center</span><span>'</span><span>,</span> <span>borderaxespad</span><span>=</span><span>0</span><span>,</span> <span>ncol</span><span>=</span><span>1</span><span>,</span> <span>fontsize</span><span>=</span><span>44</span><span>,</span> <span>edgecolor</span><span>=</span><span>"</span><span>#FAE8E0</span><span>"</span><span>)</span>
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 2.7 * len(df))) ... line = Line2D([-0.33, 1.0], [-0.9, -0.9], color=TEXT_COLOR) line.set_clip_on(False) ax.add_artist(line) title = "Lipstick Chart - Relative\nDecreases Compared\nto 2000" plt.title(title, x=-0.32, y=1.11, fontsize=58, ha="left", linespacing=1.6) plt.legend(bbox_to_anchor=(0.75, 1.14), loc='lower center', borderaxespad=0, ncol=1, fontsize=44, edgecolor="#FAE8E0")

Enter fullscreen mode Exit fullscreen mode

Here’s what the chart looks like now.


Step 7 – Creating an image and adding padding

The chart looks a bit cramped, so the last step is to add some padding. I’m doing that by turning the figure into a PIL Image with the following function.

<span>def</span> <span>create_image_from_figure</span><span>(</span><span>fig</span><span>):</span>
<span>plt</span><span>.</span><span>tight_layout</span><span>()</span>
<span>fig</span><span>.</span><span>canvas</span><span>.</span><span>draw</span><span>()</span>
<span>data</span> <span>=</span> <span>np</span><span>.</span><span>frombuffer</span><span>(</span><span>fig</span><span>.</span><span>canvas</span><span>.</span><span>tostring_rgb</span><span>(),</span> <span>dtype</span><span>=</span><span>np</span><span>.</span><span>uint8</span><span>)</span>
<span>data</span> <span>=</span> <span>data</span><span>.</span><span>reshape</span><span>((</span><span>fig</span><span>.</span><span>canvas</span><span>.</span><span>get_width_height</span><span>()[::</span><span>-</span><span>1</span><span>])</span> <span>+</span> <span>(</span><span>3</span><span>,))</span>
<span>plt</span><span>.</span><span>close</span><span>()</span>
<span>return</span> <span>Image</span><span>.</span><span>fromarray</span><span>(</span><span>data</span><span>)</span>
<span>def</span> <span>create_image_from_figure</span><span>(</span><span>fig</span><span>):</span>
    <span>plt</span><span>.</span><span>tight_layout</span><span>()</span>

    <span>fig</span><span>.</span><span>canvas</span><span>.</span><span>draw</span><span>()</span>
    <span>data</span> <span>=</span> <span>np</span><span>.</span><span>frombuffer</span><span>(</span><span>fig</span><span>.</span><span>canvas</span><span>.</span><span>tostring_rgb</span><span>(),</span> <span>dtype</span><span>=</span><span>np</span><span>.</span><span>uint8</span><span>)</span>
    <span>data</span> <span>=</span> <span>data</span><span>.</span><span>reshape</span><span>((</span><span>fig</span><span>.</span><span>canvas</span><span>.</span><span>get_width_height</span><span>()[::</span><span>-</span><span>1</span><span>])</span> <span>+</span> <span>(</span><span>3</span><span>,))</span>
    <span>plt</span><span>.</span><span>close</span><span>()</span> 

    <span>return</span> <span>Image</span><span>.</span><span>fromarray</span><span>(</span><span>data</span><span>)</span>
def create_image_from_figure(fig): plt.tight_layout() fig.canvas.draw() data = np.frombuffer(fig.canvas.tostring_rgb(), dtype=np.uint8) data = data.reshape((fig.canvas.get_width_height()[::-1]) + (3,)) plt.close() return Image.fromarray(data)

Enter fullscreen mode Exit fullscreen mode

And here’s the function to add padding.

<span>def</span> <span>add_padding_to_chart</span><span>(</span><span>chart</span><span>,</span> <span>left</span><span>,</span> <span>top</span><span>,</span> <span>right</span><span>,</span> <span>bottom</span><span>,</span> <span>background</span><span>):</span>
<span>size</span> <span>=</span> <span>chart</span><span>.</span><span>size</span>
<span>image</span> <span>=</span> <span>Image</span><span>.</span><span>new</span><span>(</span><span>"</span><span>RGB</span><span>"</span><span>,</span> <span>(</span><span>size</span><span>[</span><span>0</span><span>]</span> <span>+</span> <span>left</span> <span>+</span> <span>right</span><span>,</span> <span>size</span><span>[</span><span>1</span><span>]</span> <span>+</span> <span>top</span> <span>+</span> <span>bottom</span><span>),</span> <span>background</span><span>)</span>
<span>image</span><span>.</span><span>paste</span><span>(</span><span>chart</span><span>,</span> <span>(</span><span>left</span><span>,</span> <span>top</span><span>))</span>
<span>return</span> <span>image</span>
<span>def</span> <span>add_padding_to_chart</span><span>(</span><span>chart</span><span>,</span> <span>left</span><span>,</span> <span>top</span><span>,</span> <span>right</span><span>,</span> <span>bottom</span><span>,</span> <span>background</span><span>):</span>
    <span>size</span> <span>=</span> <span>chart</span><span>.</span><span>size</span>
    <span>image</span> <span>=</span> <span>Image</span><span>.</span><span>new</span><span>(</span><span>"</span><span>RGB</span><span>"</span><span>,</span> <span>(</span><span>size</span><span>[</span><span>0</span><span>]</span> <span>+</span> <span>left</span> <span>+</span> <span>right</span><span>,</span> <span>size</span><span>[</span><span>1</span><span>]</span> <span>+</span> <span>top</span> <span>+</span> <span>bottom</span><span>),</span> <span>background</span><span>)</span>
    <span>image</span><span>.</span><span>paste</span><span>(</span><span>chart</span><span>,</span> <span>(</span><span>left</span><span>,</span> <span>top</span><span>))</span>
    <span>return</span> <span>image</span>
def add_padding_to_chart(chart, left, top, right, bottom, background): size = chart.size image = Image.new("RGB", (size[0] + left + right, size[1] + top + bottom), background) image.paste(chart, (left, top)) return image

Enter fullscreen mode Exit fullscreen mode

We have now written all code required to create the data visualization we aimed for.

Here’s the full code snippet that uses all functions to create the final lipstick chart.

<span>fig</span><span>,</span> <span>ax</span> <span>=</span> <span>plt</span><span>.</span><span>subplots</span><span>(</span><span>nrows</span><span>=</span><span>1</span><span>,</span> <span>ncols</span><span>=</span><span>1</span><span>,</span> <span>figsize</span><span>=</span><span>(</span><span>18</span><span>,</span> <span>2.7</span> <span>*</span> <span>len</span><span>(</span><span>df</span><span>)))</span>
<span>add_bars</span><span>(</span>
<span>ax</span><span>=</span><span>ax</span><span>,</span> <span>x</span><span>=</span><span>df</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>]</span> <span>/</span> <span>df</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>],</span>
<span>width</span><span>=</span><span>0.55</span><span>,</span> <span>alpha</span><span>=</span><span>0.2</span><span>,</span> <span>label</span><span>=</span><span>"</span><span>2000</span><span>"</span>
<span>)</span>
<span>add_bars</span><span>(</span>
<span>ax</span><span>=</span><span>ax</span><span>,</span> <span>x</span><span>=</span><span>df</span><span>[</span><span>"</span><span>latest_value</span><span>"</span><span>]</span> <span>/</span> <span>df</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>],</span>
<span>width</span><span>=</span><span>0.7</span><span>,</span> <span>alpha</span><span>=</span><span>1</span><span>,</span> <span>label</span><span>=</span><span>"</span><span>Latest</span><span>"</span>
<span>)</span>
<span>ax</span><span>.</span><span>set</span><span>(</span><span>xlabel</span><span>=</span><span>None</span><span>,</span> <span>ylabel</span><span>=</span><span>None</span><span>,</span> <span>xticks</span><span>=</span><span>[])</span>
<span>ax</span><span>.</span><span>tick_params</span><span>(</span><span>"</span><span>y</span><span>"</span><span>,</span> <span>labelsize</span><span>=</span><span>28</span><span>,</span> <span>pad</span><span>=</span><span>32</span><span>)</span>
<span>ax</span><span>.</span><span>tick_params</span><span>(</span><span>"</span><span>x</span><span>"</span><span>,</span> <span>labelsize</span><span>=</span><span>20</span><span>,</span> <span>pad</span><span>=</span><span>16</span><span>)</span>
<span>ax</span><span>.</span><span>set_yticks</span><span>(</span>
<span>ticks</span><span>=</span><span>[</span><span>i</span> <span>for</span> <span>i</span> <span>in</span> <span>range</span><span>(</span><span>len</span><span>(</span><span>df</span><span>))],</span>
<span>labels</span><span>=</span><span>[</span><span>split_name</span><span>(</span><span>n</span><span>,</span> <span>limit</span><span>=</span><span>20</span><span>)</span> <span>for</span> <span>n</span> <span>in</span> <span>df</span><span>[</span><span>"</span><span>indicator_name</span><span>"</span><span>]],</span>
<span>linespacing</span><span>=</span><span>1.7</span><span>,</span> <span>va</span><span>=</span><span>"</span><span>center</span><span>"</span>
<span>)</span>
<span>for</span> <span>index</span><span>,</span> <span>row</span> <span>in</span> <span>df</span><span>.</span><span>reset_index</span><span>().</span><span>iterrows</span><span>():</span>
<span>add_info_text</span><span>(</span><span>ax</span><span>,</span> <span>row</span><span>,</span> <span>index</span><span>)</span>
<span>add_change_text</span><span>(</span><span>ax</span><span>,</span> <span>row</span><span>,</span> <span>index</span><span>)</span>
<span>line</span> <span>=</span> <span>Line2D</span><span>([</span><span>-</span><span>0.35</span><span>,</span> <span>1.0</span><span>],</span> <span>[</span><span>-</span><span>0.9</span><span>,</span> <span>-</span><span>0.9</span><span>],</span> <span>color</span><span>=</span><span>TEXT_COLOR</span><span>)</span>
<span>line</span><span>.</span><span>set_clip_on</span><span>(</span><span>False</span><span>)</span>
<span>ax</span><span>.</span><span>add_artist</span><span>(</span><span>line</span><span>)</span>
<span>title</span> <span>=</span> <span>"</span><span>Lipstick Chart - Relative</span><span>\n</span><span>Decreases Compared</span><span>\n</span><span>to 2000</span><span>"</span>
<span>plt</span><span>.</span><span>title</span><span>(</span><span>title</span><span>,</span> <span>x</span><span>=-</span><span>0.32</span><span>,</span> <span>y</span><span>=</span><span>1.11</span><span>,</span> <span>fontsize</span><span>=</span><span>58</span><span>,</span> <span>ha</span><span>=</span><span>"</span><span>left</span><span>"</span><span>,</span> <span>linespacing</span><span>=</span><span>1.6</span><span>)</span>
<span>plt</span><span>.</span><span>legend</span><span>(</span><span>bbox_to_anchor</span><span>=</span><span>(</span><span>0.75</span><span>,</span> <span>1.14</span><span>),</span> <span>loc</span><span>=</span><span>'</span><span>lower center</span><span>'</span><span>,</span> <span>borderaxespad</span><span>=</span><span>0</span><span>,</span> <span>ncol</span><span>=</span><span>1</span><span>,</span> <span>fontsize</span><span>=</span><span>44</span><span>,</span> <span>edgecolor</span><span>=</span><span>"</span><span>#FAE8E0</span><span>"</span><span>)</span>
<span>image</span> <span>=</span> <span>create_image_from_figure</span><span>(</span><span>fig</span><span>)</span>
<span>image</span> <span>=</span> <span>add_padding_to_chart</span><span>(</span><span>image</span><span>,</span> <span>20</span><span>,</span> <span>50</span><span>,</span> <span>10</span><span>,</span> <span>50</span><span>,</span> <span>BACKGROUND_COLOR</span><span>)</span>
<span>fig</span><span>,</span> <span>ax</span> <span>=</span> <span>plt</span><span>.</span><span>subplots</span><span>(</span><span>nrows</span><span>=</span><span>1</span><span>,</span> <span>ncols</span><span>=</span><span>1</span><span>,</span> <span>figsize</span><span>=</span><span>(</span><span>18</span><span>,</span> <span>2.7</span> <span>*</span> <span>len</span><span>(</span><span>df</span><span>)))</span>

<span>add_bars</span><span>(</span>
    <span>ax</span><span>=</span><span>ax</span><span>,</span> <span>x</span><span>=</span><span>df</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>]</span> <span>/</span> <span>df</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>],</span>
    <span>width</span><span>=</span><span>0.55</span><span>,</span> <span>alpha</span><span>=</span><span>0.2</span><span>,</span> <span>label</span><span>=</span><span>"</span><span>2000</span><span>"</span>
<span>)</span>

<span>add_bars</span><span>(</span>
    <span>ax</span><span>=</span><span>ax</span><span>,</span> <span>x</span><span>=</span><span>df</span><span>[</span><span>"</span><span>latest_value</span><span>"</span><span>]</span> <span>/</span> <span>df</span><span>[</span><span>"</span><span>2000</span><span>"</span><span>],</span>
    <span>width</span><span>=</span><span>0.7</span><span>,</span> <span>alpha</span><span>=</span><span>1</span><span>,</span> <span>label</span><span>=</span><span>"</span><span>Latest</span><span>"</span>
<span>)</span>

<span>ax</span><span>.</span><span>set</span><span>(</span><span>xlabel</span><span>=</span><span>None</span><span>,</span> <span>ylabel</span><span>=</span><span>None</span><span>,</span> <span>xticks</span><span>=</span><span>[])</span>
<span>ax</span><span>.</span><span>tick_params</span><span>(</span><span>"</span><span>y</span><span>"</span><span>,</span> <span>labelsize</span><span>=</span><span>28</span><span>,</span> <span>pad</span><span>=</span><span>32</span><span>)</span>
<span>ax</span><span>.</span><span>tick_params</span><span>(</span><span>"</span><span>x</span><span>"</span><span>,</span> <span>labelsize</span><span>=</span><span>20</span><span>,</span> <span>pad</span><span>=</span><span>16</span><span>)</span>

<span>ax</span><span>.</span><span>set_yticks</span><span>(</span>
    <span>ticks</span><span>=</span><span>[</span><span>i</span> <span>for</span> <span>i</span> <span>in</span> <span>range</span><span>(</span><span>len</span><span>(</span><span>df</span><span>))],</span>
    <span>labels</span><span>=</span><span>[</span><span>split_name</span><span>(</span><span>n</span><span>,</span> <span>limit</span><span>=</span><span>20</span><span>)</span> <span>for</span> <span>n</span> <span>in</span> <span>df</span><span>[</span><span>"</span><span>indicator_name</span><span>"</span><span>]],</span>
    <span>linespacing</span><span>=</span><span>1.7</span><span>,</span> <span>va</span><span>=</span><span>"</span><span>center</span><span>"</span>
<span>)</span>

<span>for</span> <span>index</span><span>,</span> <span>row</span> <span>in</span> <span>df</span><span>.</span><span>reset_index</span><span>().</span><span>iterrows</span><span>():</span>
    <span>add_info_text</span><span>(</span><span>ax</span><span>,</span> <span>row</span><span>,</span> <span>index</span><span>)</span>
    <span>add_change_text</span><span>(</span><span>ax</span><span>,</span> <span>row</span><span>,</span> <span>index</span><span>)</span>

<span>line</span> <span>=</span> <span>Line2D</span><span>([</span><span>-</span><span>0.35</span><span>,</span> <span>1.0</span><span>],</span> <span>[</span><span>-</span><span>0.9</span><span>,</span> <span>-</span><span>0.9</span><span>],</span> <span>color</span><span>=</span><span>TEXT_COLOR</span><span>)</span>
<span>line</span><span>.</span><span>set_clip_on</span><span>(</span><span>False</span><span>)</span>
<span>ax</span><span>.</span><span>add_artist</span><span>(</span><span>line</span><span>)</span>

<span>title</span> <span>=</span> <span>"</span><span>Lipstick Chart - Relative</span><span>\n</span><span>Decreases Compared</span><span>\n</span><span>to 2000</span><span>"</span>
<span>plt</span><span>.</span><span>title</span><span>(</span><span>title</span><span>,</span> <span>x</span><span>=-</span><span>0.32</span><span>,</span> <span>y</span><span>=</span><span>1.11</span><span>,</span> <span>fontsize</span><span>=</span><span>58</span><span>,</span> <span>ha</span><span>=</span><span>"</span><span>left</span><span>"</span><span>,</span> <span>linespacing</span><span>=</span><span>1.6</span><span>)</span>
<span>plt</span><span>.</span><span>legend</span><span>(</span><span>bbox_to_anchor</span><span>=</span><span>(</span><span>0.75</span><span>,</span> <span>1.14</span><span>),</span> <span>loc</span><span>=</span><span>'</span><span>lower center</span><span>'</span><span>,</span> <span>borderaxespad</span><span>=</span><span>0</span><span>,</span> <span>ncol</span><span>=</span><span>1</span><span>,</span> <span>fontsize</span><span>=</span><span>44</span><span>,</span> <span>edgecolor</span><span>=</span><span>"</span><span>#FAE8E0</span><span>"</span><span>)</span>

<span>image</span> <span>=</span> <span>create_image_from_figure</span><span>(</span><span>fig</span><span>)</span>
<span>image</span> <span>=</span> <span>add_padding_to_chart</span><span>(</span><span>image</span><span>,</span> <span>20</span><span>,</span> <span>50</span><span>,</span> <span>10</span><span>,</span> <span>50</span><span>,</span> <span>BACKGROUND_COLOR</span><span>)</span>
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(18, 2.7 * len(df))) add_bars( ax=ax, x=df["2000"] / df["2000"], width=0.55, alpha=0.2, label="2000" ) add_bars( ax=ax, x=df["latest_value"] / df["2000"], width=0.7, alpha=1, label="Latest" ) ax.set(xlabel=None, ylabel=None, xticks=[]) ax.tick_params("y", labelsize=28, pad=32) ax.tick_params("x", labelsize=20, pad=16) ax.set_yticks( ticks=[i for i in range(len(df))], labels=[split_name(n, limit=20) for n in df["indicator_name"]], linespacing=1.7, va="center" ) for index, row in df.reset_index().iterrows(): add_info_text(ax, row, index) add_change_text(ax, row, index) line = Line2D([-0.35, 1.0], [-0.9, -0.9], color=TEXT_COLOR) line.set_clip_on(False) ax.add_artist(line) title = "Lipstick Chart - Relative\nDecreases Compared\nto 2000" plt.title(title, x=-0.32, y=1.11, fontsize=58, ha="left", linespacing=1.6) plt.legend(bbox_to_anchor=(0.75, 1.14), loc='lower center', borderaxespad=0, ncol=1, fontsize=44, edgecolor="#FAE8E0") image = create_image_from_figure(fig) image = add_padding_to_chart(image, 20, 50, 10, 50, BACKGROUND_COLOR)

Enter fullscreen mode Exit fullscreen mode

And here’s the finished product.

We’re done!


Conclusion

Thank you for reading this tutorial; I hope you learned some tricks you can reuse for your data visualization projects.

If you want to see more tutorials and beautiful data visualizations, follow me here, subscribe to Data Wonder, and to oscarl3o on Twitter.

See you next time.

原文链接:How to Create a Lipstick Chart With Matplotlib

© 版权声明
THE END
喜欢就支持一下吧
点赞6 分享
Don’t let a bad day make you feel lke you have a bad lfe.
不要让糟糕的一天让你误以为有个糟糕的人生
评论 抢沙发

请登录后发表评论

    暂无评论内容