As mentioned in the instructions, all materials can be open in Colab as Jupyter notebooks. In this way users can run the code in the cloud. It is highly recommanded to follow the tutorials in the right order.

Welcome to the data visualization chapter! After you have done some basic plots using Matplotlib, do you know you can further style your plot beyond the color uses? In this lesson, you will learn how can you make a matplotlib chart with hand drawn style ✍️. To do that you do not need to install any new library.

Let's try to make a chart using some Chinese historical statistics about taxation and infrastructures (stage station) during Yuan Dynasty (1279-1368) [Source].

To begin, we need to first import some libraries and install pinyin for converting the Chinese labels.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
! pip install pinyin
import pinyin

We have our locations listed. They are all different Chinese regions in which stage stations are located. Using pinyin.get() we can convert the words into pinyin.

loc_list = ["腹里","河南江北","辽阳","江浙","江西","湖广","陕西","四川","云南","甘肃"]

name = [pinyin.get(loc, format="strip", delimiter=" ") for loc in loc_list]

Then we will define the type for the stage station, either land transport or water transport.

type_list = np.concatenate((np.repeat("Lu zhan",10), np.repeat("Shui zhan", 10)), axis=0)

Now, we can construct our data frame.

data = { 
    "Location": name + name,
    "Station": [177,106,120,180,85,100,80,48,74,6,21,90,0,82,69,73,1,84,4,0],
    "Type": type_list
        }

df = pd.DataFrame(data=data)
df.head()
Location Station Type
0 fu li 177 Lu zhan
1 liao yang 106 Lu zhan
2 he nan 120 Lu zhan
3 shan xi 180 Lu zhan
4 si chuan 85 Lu zhan

We can use seaborn sns.catplot() for making a groupped bar chart easily. We will group the variable using argument hue. For further adjustments, we can add a title, rotate the ticks, and add annotations to the chart. Seaborn is a plotting library based on matplotlib and it is highly compatible with Pandas. This means, you can plot a Pandas dataframe using seaborn which enable users to create stylist chart in different themes. Let's look at a introduction video.

Now, Let's look at how a seaborn chart is like without hand drawn style.

import seaborn as sns
sns.set_style('darkgrid')

# groupped bar chart
ax = sns.catplot(x = "Location",       # x variable name
            y = "Station",       # y variable name
            hue = "Type",  # group variable name
            data = df,     # dataframe to plot
            kind = "bar",
            height=8)

# add a title
plt.title("Count of Stage Stations\n in Yuan Dynasty (1279-1368)",loc="left",fontsize=22)

# rotate ticks
plt.xticks(rotation=30)

# add annotations
plt.annotate('FOR WATER TRANSPORT', xy=(2.9,125), xytext=(4.5,145),
             arrowprops=dict(facecolor='black', shrink=0.05, headwidth=20, width=5))

plt.annotate('FOR LAND TRANSPORT', xy=(3.1,80), xytext=(4.5,125),
             arrowprops=dict(facecolor='black', shrink=0.05, headwidth=20, width=5))

# display plot
plt.show()

In fact, we can alter the style of seaborn chart simply using sns.set_style(). Available style includes "darkgrid","white","ticks", and "whitegrid". Let's look at the same plot in "white" style.

import seaborn as sns
sns.set_style('white')

# groupped bar chart
ax = sns.catplot(x = "Location",       # x variable name
            y = "Station",       # y variable name
            hue = "Type",  # group variable name
            data = df,     # dataframe to plot
            kind = "bar",
            height=8)

# add a title
plt.title("Count of Stage Stations\n in Yuan Dynasty (1279-1368)",loc="left",fontsize=22)

# rotate ticks
plt.xticks(rotation=30)

# add annotations
plt.annotate('FOR WATER TRANSPORT', xy=(2.9,125), xytext=(4.5,145),
             arrowprops=dict(facecolor='black', shrink=0.05, headwidth=20, width=5))

plt.annotate('FOR LAND TRANSPORT', xy=(3.1,80), xytext=(4.5,125),
             arrowprops=dict(facecolor='black', shrink=0.05, headwidth=20, width=5))

# display plot
plt.show()

Hand Drawn Style

To plot the chart with hand drawn style, we only need to add plt.xkcd() before the plotting function. Matplotlib xkcd is a sketch-style drawing mode and it will only has effects on things drawn after plt.xkcd() is called.

import seaborn as sns
sns.set_style('white')

# hand drawn chart
plt.xkcd()

# groupped bar chart
ax = sns.catplot(x = "Location",       # x variable name
            y = "Station",       # y variable name
            hue = "Type",  # group variable name
            data = df,     # dataframe to plot
            kind = "bar",
            height=8)

# add a title
plt.title("Count of Stage Stations\n in Yuan Dynasty (1279-1368)",loc="left",fontsize=22)

# rotate ticks
plt.xticks(rotation=30)

# add annotations
plt.annotate('FOR WATER TRANSPORT', xy=(2.9,125), xytext=(4.5,145),
             arrowprops=dict(facecolor='black', shrink=0.05, headwidth=20, width=5))

plt.annotate('FOR LAND TRANSPORT', xy=(3.1,80), xytext=(4.5,125),
             arrowprops=dict(facecolor='black', shrink=0.05, headwidth=20, width=5))

# display plot
plt.show()

We can also try with a different plotting type. Let's try to do a pie chart using the taxation data from different Chinese regions. The same as above, we need to first creating the pandas data frame, following by the plotting function using plt.subplots() and pie(). As we already use plt.xkcd() above, our plot will be automatically create in the hand drawn style. For the pie function, we will use rotatelabels to avoid label overlapping and labeldistance to define the label locations.

loc_list = ["腹里","辽阳","河南","陕西","四川","甘肃","云南","江浙","江西","湖广"]
name = [pinyin.get(loc, format="strip", delimiter=" ") for loc in loc_list] # list comprehension to get pinyin for the whole list

# create data
data = {
    "Location": name,
    "Amount": [18.75,0.59,21.39,1.86,0.96,0.50,2.29,37.10,9.56,6.97] 
}

# pass data into data frame
df = pd.DataFrame(data=data)

# plot figure
fig1, ax1 = plt.subplots(figsize=(10,10))

# draw pie chart
ax1.pie(df.Amount,labels=df.Location, autopct='%1.1f%%',labeldistance=1,rotatelabels=True,shadow=True, startangle=90)
ax1.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.

# title
plt.title("Yuan Dai Sui Ru Liang Shu\n(1279-1368)", loc='left')
plt.show()

Great! Now we can style our graphics for more eye-catching presentation of the data.

Previous Lesson: Introduction to Data Visualization

Next Lesson: Simple Bubble Chart




Additional information

This notebook is provided for educational purpose and feel free to report any issue on GitHub.


Author: Ka Hei, Chow

License: The code in this notebook is licensed under the Creative Commons by Attribution 4.0 license.

Last modified: January 2022