Slope charts with Python’s Matplotlib | by Thiago Carvalho | Towards Data Science

With a straightforward format that can effortlessly illustrate changes and rank variables, Slope charts are more than just an over-glorified line chart.
They have earned their place in data visualization and can be a great addition to your reports and dashboards.
In this article, we’ll explore how to plot them with Matplotlib, get a look at different ways of designing them and how they compare to other data visualizations.
The data we’ll use in the following examples is the GDP per capita from the UN. I used filters to download only 2018 and 2019 data.
import pandas as pdimport matplotlib.pyplot as pltdf = pd.read_csv('../data/UNdata_gdp.csv')df.head()
Let’s start by plotting a single line chart for a country.
temp = df[df['Country or Area'] == 'Switzerland']plt.plot(temp.Year, temp.Value)plt.show()
We’ll need to repeat that for a list of countries to plot the other lines. We can also start preparing our visualization layout by adding a figure with a custom size, fixing the x ticks, and increasing the space in the x-axis to add labels.
Labels at the start and end of the lines are a distinguishable feature of slope charts; they can display different information to fit our visualization's purpose.
countries = ['Ireland', 'Norway',             'Switzerland', 'Cayman Islands',             'China, Macao Special Administrative Region']fig, ax = plt.subplots(1, figsize=(10,10))for i in countries:    temp = df[df['Country or Area'] == i]    plt.plot(temp.Year, temp.Value)    plt.xlim(2017.5,2019.5)plt.xticks([2018, 2019])plt.show()
Cool, It’s starting to look more like a Slope chart, but we’re not there yet.
Let’s add the labels and format the y-ticks.
countries = ['Ireland', 'Norway',             'Switzerland', 'Cayman Islands',             'China, Macao Special Administrative Region']fig, ax = plt.subplots(1, figsize=(10,10))for i in countries:    # get a single country from the list    temp = df[df['Country or Area'] == i]    # plot the lines    plt.plot(temp.Year, temp.Value, marker='o', markersize=5)    # replace large labels    if i == 'China, Macao Special Administrative Region':        i = 'Macao (China)'    # end label    plt.text(temp.Year.values[0]+0.02, temp.Value.values[0], i)    # start label    plt.text(temp.Year.values[1]-0.02, temp.Value.values[1], i, ha='right')    # x limits, x ticks, and y label plt.xlim(2017.5,2019.5)plt.xticks([2018, 2019])# get y ticks, replace 1,000 with k, and draw the ticksyticks = plt.yticks()[0]plt.yticks(yticks, ['{}k'.format(i/1000) for i in yticks])plt.show()
That’s it! We have a slope chart.
The labels with the names of the countries/ areas make it incredibly easy to follow the information, way more accessible than a legend. It also ranks the variables both before and after the change.
Let’s add some more detail to our Slope chart before exploring other applications.
We’ll remove the spines, add gridlines, a y-axis label, title, and change some colors.
countries = ['Ireland', 'Norway',             'Switzerland', 'Cayman Islands',             'China, Macao Special Administrative Region']colors = ['#769465', '#69BDE0', '#E06D5E', '#2F7694', '#94E069']fig, ax = plt.subplots(1, figsize=(10,10), facecolor='darkgrey')ax.set_facecolor('darkgrey')for i, v in enumerate(countries):    # get a single country from the list    temp = df[df['Country or Area'] == v]    # plot the lines    plt.plot(temp.Year, temp.Value,              color=colors[i], lw=2.5,              marker='o', markersize=5)    # replace large labels    if v == 'China, Macao Special Administrative Region':        v = 'Macao (China)'    # end label    plt.text(temp.Year.values[0]+0.02, temp.Value.values[0], v)    # start label    plt.text(temp.Year.values[1]-0.02, temp.Value.values[1], v, ha='right')    # x limits, x ticks, and y label plt.xlim(2017.5,2019.5)plt.xticks([2018, 2019])plt.ylabel('USD')# get y ticks, replace 1,000 with k, and draw the ticksyticks = plt.yticks()[0]plt.yticks(yticks[1:-1], ['{}k'.format(i/1000) for i in yticks[1:-1]])# gridax.xaxis.grid(color='black', linestyle='solid', which='both', alpha=0.9)ax.yaxis.grid(color='black', linestyle='dashed', which='both', alpha=0.1)# remove spinesax.spines['right'].set_visible(False)ax.spines['left'].set_visible(False)ax.spines['bottom'].set_visible(False)ax.spines['top'].set_visible(False)plt.title('GDP Per Capta\n', loc='left', fontsize=20)plt.show()
The labels are typically used for two main purposes, naming the line or displaying the values.
Sometimes, knowing the exact values is essential to our viz, and we might need to sacrifice the names to display them.
countries = ['Ireland', 'Norway',             'Switzerland', 'Cayman Islands',             'China, Macao Special Administrative Region']colors = ['#769465', '#69BDE0', '#E06D5E', '#2F7694', '#94E069']fig, ax = plt.subplots(1, figsize=(10,10), facecolor='darkgrey')ax.set_facecolor('darkgrey')for i, v in enumerate(countries):    temp = df[df['Country or Area'] == v]    plt.plot(temp.Year, temp.Value, color=colors[i], lw=2.5)                plt.text(temp.Year.values[0]+0.02,              temp.Value.values[0],              '{:,.2f}'.format(temp.Value.values[0]))        plt.text(temp.Year.values[1]-0.02,              temp.Value.values[1],              '{:,.2f}'.format(temp.Value.values[1]), va='center', ha='right')plt.xlim(2017.5,2019.5)plt.xticks([2018, 2019])yticks = plt.yticks()[0]plt.yticks([])# gridax.xaxis.grid(color='black', linestyle='solid', which='both', alpha=0.9)# remove spinesax.spines['right'].set_visible(False)ax.spines['left'].set_visible(False)ax.spines['bottom'].set_visible(False)ax.spines['top'].set_visible(False)plt.title('GDP Per Capta\n', loc='left', fontsize=20)for i, v in enumerate(countries):    if v == 'China, Macao Special Administrative Region':        countries[i] = 'Macao (China)'plt.legend(countries, loc='upper left', frameon=False)plt.show()
It’s still easy to understand what each line represents, but the rankings are not so explicit when we use a legend instead of the labels.
In some cases, we might be able to have the cake and eat it too, but it depends on the data. That is to say — If the lines are spaced enough you might be able to write the names above or below them.
colors = ['#87B38D', '#477998', '#291F1E', '#BC9CB0', '#A3333D']countries = ['Germany', 'Canada',             'Spain', 'Italy', 'France']fig, ax = plt.subplots(1, figsize=(10,10))for i, v in enumerate(countries):    temp = df[df['Country or Area'] == v]    plt.plot(temp.Year, temp.Value, color=colors[i], lw=2.5)                plt.text(temp.Year.values[0]+0.02,              temp.Value.values[0],              '{:,.2f}'.format(temp.Value.values[0]))        plt.text(temp.Year.values[1]-0.02,              temp.Value.values[1],              '{:,.2f}'.format(temp.Value.values[1]),              va='center', ha='right')        correction = 0    if v == 'Canada': correction = 500    plt.text(2018.5,              temp.Value.values[1] - correction,              v, color=colors[i],             va='center', ha='center', fontsize=14)plt.xlim(2017.5,2019.5)plt.xticks([2018, 2019])plt.yticks([])# gridax.xaxis.grid(color='black', linestyle='solid',               which='both', alpha=0.9)# remove spinesax.spines['right'].set_visible(False)ax.spines['left'].set_visible(False)ax.spines['bottom'].set_visible(False)ax.spines['top'].set_visible(False)plt.title('GDP Per Capta\n', loc='left', fontsize=20)plt.show()
Slope charts are generally simple, there are a few different approaches to them, and they may require some tweaks to fit your solution, but overall you can have a meaningful graph with very few elements.
There are no doubts you can visualize changes and display this same information with other data visualizations.
With bar charts and arrow charts, you can order your data by the initial value, the end value, or amount/ percentage of change. You would need multiple charts to display the rankings before and after, and it just isn’t the same.
None can display the rankings so naturally as Slope charts.
Even if the order of the variables isn’t essential to your visualization, Slope charts do a great job at communicating changes and adding variety to your reports and dashboards.
You can find the code for all the visualizations used in this article here.
Thanks for reading my article. I hope you enjoyed it.
More Python DataViz tutorials.