|

Create Eye-Catching Radial Bar Charts With Matplotlib

Radial bar charts are a visually attractive alternative to traditional bar charts. Data are plotted on a polar coordinate system instead of the conventional cartesian coordinate system. This allows the bars to be represented by rings rather than as vertical bars.

Radial bar charts can make a great and visually appealing graphic to include in a presentation or poster if you are looking to catch the reader’s attention. However, as with many data visualisations, they have their own drawbacks. One issue that can arise is that they can be challenging to interpret. This is because our visual system is much better at interpreting straight lines when comparing values between categories. Additionally, rings towards the centre of the radial bar chart become harder to read and compare with those further out.

This article will show how to create a visually appealing radial bar plot using the matplotlib library from Python.

When matplotlib is mentioned, most people think about basic charts that are poorly formatted and need multiple lines of awkward or confusing code to display a great chart.

Creating a Radial Bar Plot With Matplotlib

Importing Libraries and Loading Data

The first step in creating our radial bar chart is to import the libraries we are going to use. For this tutorial, we will need to import matplotlibpandas and numpy.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

After the libraries are imported, we can load or create some data. One of the most common formats for storing data in Python is the pandas dataframe.

Data can be loaded into a dataframe from a CSV file using the pd.read_csv() function or created manually from lists or dictionaries.

For this tutorial, we will create a dataframe using dummy lithology data. We will have multiple lithologies and a count of how often that lithology appears within a specific interval of a well.

To create our dataframe, we first create a dictionary with two keys: LITH and COUNT, and the values for each item will be lists containing the lithology name and the count of each lithology.

lith_dict = {'LITH': ['Shale', 'Sandstone', 
'Sandstone/Shale', 'Chalk',
'Limestone', 'Marl', 'Tuff'],
'COUNT': [40,65, 40, 35,
40, 70, 50]}

df = pd.DataFrame.from_dict(lith_dict)

Once the data has been loaded, we need to find out two things:

  • The maximum value of our COUNT column. This will give us the maximum value for our rings.
  • The total number of entries in the dataframe
max_value_full_ring = max(df['COUNT'])
data_len = len(df)

Choosing Colours and Setting Labels

The next step in creating the radial bar chart is to define the colours and the labels that will be displayed.

ring_colours = ['#2f4b7c', '#665191', '#a05195','#d45087',
'#f95d6a','#ff7c43','#ffa600']

Choosing colours for plots can be very subjective.

There are numerous tools and articles out there that can help when choosing an effective colour palette for a chart. Most of which is based on colour theory.

For this plot, I have based the colours on the following website:

https://www.learnui.design/tools/data-color-picker.html

The tool allows you to select up to 8 colours when building a palette, and also allows you to copy the hex codes, which can then be pasted directly into your code.

Palette generator tool from The Data Viz Color Picker. Image by the author.

To set up the labels, we will need to create a list comprehension that loops over the lithology name and the count. This is then joined together within a formatted string in the form of Lithology (Count).

Also, at the start of the string, we can add a few spaces. This is an easy way to add some padding between the labels and the start of the rings.

ring_labels =  [f'   {x} ({v}) ' for x, v in zip(list(df['LITH']), 
list(df['COUNT']))]

When we check on the ring_labels variable, we get back the following list:

['   Shale (40) ',
' Sandstone (65) ',
' Sandstone/Shale (40) ',
' Chalk (35) ',
' Limestone (40) ',
' Marl (70) ',
' Tuff (50) ']

Creating the Radial Bar Chart Figure With Matplotlib

Now that the data has been loaded, we can focus on building the plot.

To create the plot, we first begin by creating the figure as we would with any other matplotlib chart. We will also pass in a few parameters to the plt.figure() call. The first is the figure size, which we will set to 10 x 10. This can be set to any size you want, but this size gives a good plot for viewing on screen.

Next, we will pass in the linewidth and edgecolor parameters. These will add a 10 px border around our plot which will have a slightly different colour to the plot background.

Finally, we will set the facecolor to a very dark blue.

fig = plt.figure(figsize=(10,10), linewidth=10,
edgecolor='#393d5c',
facecolor='#25253c')

If we run the code above, we will get the following square figure displayed, which has our border and main figure background.

Background and border for the radial bar graph. Image by the author.

Adding a Polar Axis

The next step is to add an axis to our chart that uses polar coordinates rather than cartesian coordinates.

But, before we add the axis, we first have to create the shape of the axis.

This is done by creating a variable called rect and assigning it to a list containing 4 numbers. These numbers represent the starting position (x and y coordinates), the height and the width.

If we want to add some padding to our radial bar chart, we need to set the width and height parameters to a value less than 1. In this case, we will set it to 0.8, representing 80% of the available width and height.

rect = [0.1,0.1,0.8,0.8]

We can then create a new axis using fig.add_axes and pass in the rect list, along with setting the polar argument to true and removing the axis frame.

Following that, we need to set the radial bars to start from the top of the plot, which is North (N), and we will set the bars to radiate in a counter-clockwise direction. If we wanted the bars to go clockwise, then we would change the set_theta_direction() to -1.

# Add axis for radial backgrounds
ax_polar_bg = fig.add_axes(rect, polar=True, frameon=False)
# Start bars at top of plot
ax_polar_bg.set_theta_zero_location('N')
# Make bars go counter-clockwise.
ax_polar_bg.set_theta_direction(1)

Adding Faint Background Rings to the Radial Bar Plot

To add some visual interest to our plot, we will add some faint bars that go from 0 to the maximum value. This gives the illusion of bar portions that have yet to be filled.

# Loop through each entry in the dataframe and plot a grey
# ring to create the background for each one
for i in range(data_len):
ax_polar_bg.barh(i, max_value_full_ring*1.5*np.pi/max_value_full_ring,
color='grey',
alpha=0.1)

As we want a space for our labels in the top right of our plot, we will set the bars only to complete 3/4 of a full circle. This is done with the following piece of code, which is passed into the call to ax_polar_bg.barh.

max_value_full_ring*1.5*np.pi/max_value_full_ring

If we run our code at this point, we will now see the plot below and the beginnings of our radial bar plot.

Radial bar plot showing the polar axis before data is added. Image by the author.

We can hide the polar axis simply by calling .axis() and passing in the word 'off'.

# Hide all axis items
ax_polar_bg.axis('off')

When we run the code again, we will see we have a clean plot with empty radial bars.

Faint radial bars to show 0 to 100% used for creating the background. Image by the author.

Adding Coloured Rings to the Radial Bar Plot

Now we are ready to add some colour to our plot.

To do this, we will add a new axis to our figure, which uses very similar code to adding the faint background bars.

Within the set_rgrids() function, we will pass in a list with 0 to 6. These numbers represent the radii for the radial gridlines. Also, we will pass in the labels and set their appearance within this function. To have the labels appear in the top right of our plot and adjacent to the starting point of the rings, we need to set the angle to 0.

Once the radial grid has been set up, we need to loop through each category within the dataframe and add a ring to the chart using the barh() function within matplotlib.

As with the previous section of code, we only want the rings to go 3/4 of the way around, so we need to multiply pi by 1.5 instead of 2.


# Add axis for radial chart for each entry in the dataframe
ax_polar = fig.add_axes(rect, polar=True, frameon=False)
ax_polar.set_theta_zero_location('N')
ax_polar.set_theta_direction(1)
ax_polar.set_rgrids([0, 1, 2, 3, 4, 5, 6],
labels=ring_labels,
angle=0,
fontsize=14, fontweight='bold',
color='white', verticalalignment='center')

# Loop through each entry in the dataframe and create a coloured
# ring for each entry
for i in range(data_len):
ax_polar.barh(i, list(df['COUNT'])[i]*1.5*np.pi/max_value_full_ring,
color=ring_colours[i])

When we run our code now, we will get the following plot which is 95% done.

Radial bar chart with polar gridlines and tick labels. Image by the author.

Hiding Polar Grid Lines from the Matplotlib Polar Plot

Finally, we need to remove the polar gridlines, ticks, and associated labels. We can do that like so:

# Hide all grid elements for the    
ax_polar.grid(False)
ax_polar.tick_params(axis='both', left=False, bottom=False,
labelbottom=False, labelleft=True)

plt.show()

Which then generates our final radial bar chart figure.

Final radial bar plot generated with matplotlib. Image by the author.

Full Python Code to Generate a Radial Bar Plot

Here is the complete python code for generating the above radial bar chart with matplotlib.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

#Load data into pandas dataframe

lith_dict = {'LITH': ['Shale', 'Sandstone',
'Sandstone/Shale', 'Chalk',
'Limestone', 'Marl', 'Tuff'],
'COUNT': [40,65, 40, 35,
40, 70, 50]}

df = pd.DataFrame.from_dict(lith_dict)

# Get key properties for colours and labels
max_value_full_ring = max(df['COUNT'])

ring_colours = ['#2f4b7c', '#665191', '#a05195','#d45087',
'#f95d6a','#ff7c43','#ffa600']

ring_labels = [f' {x} ({v}) ' for x, v in zip(list(df['LITH']),
list(df['COUNT']))]
data_len = len(df)

# Begin creating the figure
fig = plt.figure(figsize=(10,10), linewidth=10,
edgecolor='#393d5c',
facecolor='#25253c')

rect = [0.1,0.1,0.8,0.8]

# Add axis for radial backgrounds
ax_polar_bg = fig.add_axes(rect, polar=True, frameon=False)
ax_polar_bg.set_theta_zero_location('N')
ax_polar_bg.set_theta_direction(1)

# Loop through each entry in the dataframe and plot a grey
# ring to create the background for each one
for i in range(data_len):
ax_polar_bg.barh(i, max_value_full_ring*1.5*np.pi/max_value_full_ring,
color='grey',
alpha=0.1)
# Hide all axis items
ax_polar_bg.axis('off')

# Add axis for radial chart for each entry in the dataframe
ax_polar = fig.add_axes(rect, polar=True, frameon=False)
ax_polar.set_theta_zero_location('N')
ax_polar.set_theta_direction(1)
ax_polar.set_rgrids([0, 1, 2, 3, 4, 5, 6],
labels=ring_labels,
angle=0,
fontsize=14, fontweight='bold',
color='white', verticalalignment='center')

# Loop through each entry in the dataframe and create a coloured
# ring for each entry
for i in range(data_len):
ax_polar.barh(i, list(df['COUNT'])[i]*1.5*np.pi/max_value_full_ring,
color=ring_colours[i])


# Hide all grid elements for the
ax_polar.grid(False)
ax_polar.tick_params(axis='both', left=False, bottom=False,
labelbottom=False, labelleft=True)

plt.show()

Summary

Radial bar charts provide a visually appealing alternative to traditional bar charts and can easily be created using Python’s matplotlib library. Within this article, we have seen how to build up an eye-catching radial bar chart from scratch using matplotlib, which can easily be used in a poster presentation or infographic.

Similar Posts

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *