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.
暂无评论内容