Techno Blender
Digitally Yours.

Create Stunning Radar Plots with Matplotlib | by Andy McDonald | Apr, 2023

0 53


Matplotlib radar plot with cyberpunk theming. Image by the author.

Radar plots (also known as spider plots or radar charts) are a popular data visualisation tool that allows us to compare datasets by displaying multiple variables simultaneously on a 2-dimensional plot.

Each variable is represented by a spoke extending from the plot’s centre to the edge, and the magnitude of that variable is represented by how far along the spoke it is. Lines are then drawn between each of the variables to form a web-like shape.

Within geoscience and petrophysics, we can use radar plots to compare how lithologies vary between wells or display mineralogy variations between rock samples.

Within this tutorial, I will illustrate how we can create a radar plot using some synthetic lithology data. The data represents the average lithologies encountered within a well.

Let’s get started!

To get started, we will need to import two libraries: numpy and matplotlib.

import matplotlib.pyplot as plt
import numpy as np

Next, we can create some dummy data.

Traditionally, this data may already by contained within a pandas dataframe. If it is, then it is recommended to convert the required columns to lists before proceeding.

lithologies = ['Shale', 'Sandstone', 
'Limestone', 'Dolomite',
'Anhydrite', 'Coal', 'Tuff']

well1 = [47, 35, 10, 1, 0, 2, 5]

well2 = [7, 10, 51, 22, 10, 0, 0]

Before we can use the data, we need to ensure that the areas we plot on the radar plot create a closed polygon.

To do this, we need to take all of the elements in the list and then append the first element to the end of the list.

lithologies = [*lithologies, lithologies[0]]
well1 = [*well1, well1[0]]
well2 = [*well2, well2[0]]

If we call upon well2, we will get back the following list of values and we will see that the first number is now also at the end of the list.

[7, 10, 51, 22, 10, 0, 0, 7]

To begin constructing the radar plot, we will first need to sort the positions of the labels from the lithologies list. These will be equally spaced around the edge of the polar plot.

label_loc = np.linspace(start=0, stop=2 * np.pi, num=len(lithologies))

Next, we can move on to creating the radar plot figure.

First, we need to define the figure, which will be created using plt.subplots. Within the subplot_kw parameter, we need to specify that we want a polar plot.

Following that, we will add two axes to the plot and pass in the label_loc variable along with the well1 and well2 lists.

Then, we will create the polar grid using a call to plt.thetagrids() and here, we will pass in the label locations and the lithology labels.

fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

plt.show()

When we run the above code, we will return the following radar plot.

A basic radar plot created with matplotlib. Image by the author.

What we get back looks good for a basic radar plot. However, we can improve it with a few tweaks.

One way we can improve the radar plot is by adding a transparent fill to the two areas.

This is done using ax.fill() and passing in label_loc , the relevant well list containing the values, and setting the opacity to 0.3 using the alpha parameter.

fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

ax.fill(label_loc, well1, alpha=0.3)
ax.fill(label_loc, well2, alpha=0.3)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

plt.show()

When we run the above code, we now have the following radar plot with the areas filled in.

A basic radar plot created with matplotlib showing area fills. Image by the author.

You will notice that the labels in the previous plot look small and overlap the lines.

We can fix this by setting the tick_params and changing the padding and labelsize.

fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

ax.fill(label_loc, well1, alpha=0.3)
ax.fill(label_loc, well2, alpha=0.3)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

ax.tick_params(axis='both', which='major', pad=30, labelsize=15)

plt.show()

We get a plot with much more readable labels when we run the code.

A basic radar plot created with matplotlib showing area fills, and after adjusting the label padding and size. Image by the author.

The previous plot forms a good radar plot that can be used in reports or presentations. However, if we want to stylise it, we can use one of the many matplotlib theme libraries.

If you want to see what libraries are available, then I recommend checking out my previous article, which looks at 4 popular themes.

The cyberpunk theme is one of my favourite themes for creating stylish plots in matplotlib. However, it is purely for aesthetic reasons, and you should always consider your audience and ensure maximum readability.

We can use the cyberpunk theme by importing the library and adding a with statement

import mplcyberpunk

with plt.style.context('cyberpunk'):
fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

ax.fill(label_loc, well1, alpha=0.3)
ax.fill(label_loc, well2, alpha=0.3)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

ax.tick_params(axis='both', which='major', pad=30, labelsize=15)

plt.show()

We can now see that the plot has changed dramatically by adding two lines of code. However, the grid lines are a little faint for my liking.

Matplotlib radar plot after applying a cyberpunk theme. Image by the author.

We can lighten the lines by adding a few additional pieces of code.

Changing the grid lines is done using ax.grid() and setting the color and alpha parameters to white and 0.3, respectively.

In order to add the outer ring for the radar plot, we need to set up a custom tuple containing 4 values: red, green, and blue colour values and an alpha value.

We can then pass this into a call to ax.spines['polar'].set_color()

with plt.style.context('cyberpunk'):
fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

ax.fill(label_loc, well1, alpha=0.3)
ax.fill(label_loc, well2, alpha=0.3)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

ax.tick_params(axis='both', which='major', pad=30, labelsize=15)

ax.spines['polar'].set_linewidth(3)

edge_color = (1, 1, 1, 0.2)
ax.spines['polar'].set_color(edge_color)

ax.grid(color='white', alpha=0.3)

plt.show()

When we run the code, we now have the following radar plot with the radial grid lines. We can play around with the colour and transparency to get the effect we want.

However, bear in mind we do not want to have the lines too bright that they will distract the reader from the main data.

Matplotlib radar plot with cyberpunk theme and visible gridlines. Image by the author.

To finish the styling we can set the grid lines so that they range from and to a number that we want. This will make the outer ring feel more balanced with the rest of the rings.

We can do this by setting the ax.set_ylim() and passing in our min and max values.

with plt.style.context('cyberpunk'):
fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

ax.fill(label_loc, well1, alpha=0.3)
ax.fill(label_loc, well2, alpha=0.3)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

ax.tick_params(axis='both', which='major', pad=30, labelsize=15)

ax.spines['polar'].set_linewidth(3)

edge_color = (1, 1, 1, 0.2)
ax.spines['polar'].set_color(edge_color)

ax.grid(color='white', alpha=0.3)

ax.set_ylim(0, 60)

plt.show()

We now have a much better-looking radar plot.

Matplotlib radar plot with a cyberpunk theme and fixing the range of the rings. Image by the author.

To finish off our plot, we can help the reader understand the plot better, by adding a legend. This will allow the reader to know what area is what.

We could simply add some labels in the ax.plot() calls and then call upon ax.legend, however, this would only add lines to our legend.

If we want to add small rectangles representing the shaded area, we must create some patches first.

This is done by importing Patch from matplotlib.patches.

The created patches are then passed into the ax.legend call.

from matplotlib.patches import Patch

with plt.style.context('cyberpunk'):
fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

ax.fill(label_loc, well1, alpha=0.3)
ax.fill(label_loc, well2, alpha=0.3)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

ax.tick_params(axis='both', which='major', pad=30, labelsize=15)

ax.spines['polar'].set_linewidth(3)

edge_color = (1, 1, 1, 0.2)
ax.spines['polar'].set_color(edge_color)

ax.grid(color='white', alpha=0.3)

ax.set_ylim(0, 60)

# Create custom legend handles
well1_legend = Patch(facecolor='C0', alpha=0.5, label='Well 1')
well2_legend = Patch(facecolor='C1', alpha=0.5, label='Well 2')

# Add a legend with custom position and handles
ax.legend(handles=[well1_legend, well2_legend],
bbox_to_anchor=(1.3, 0.2), fontsize=20,
frameon=True)

plt.show()

And when we run the code we now have the finished plot.

Matplotlib radar plot with cyberpunk theming. Image by the author.

Radar plots provide a nice data visualisation and can easily be created using matplotlib. With additional style from the Cyberpunk theme library, we can take our radar plot to the next level and make it stylish.

Why don’t you give radar plots a go on your next data visualisation project.


Matplotlib radar plot with cyberpunk theming. Image by the author.

Radar plots (also known as spider plots or radar charts) are a popular data visualisation tool that allows us to compare datasets by displaying multiple variables simultaneously on a 2-dimensional plot.

Each variable is represented by a spoke extending from the plot’s centre to the edge, and the magnitude of that variable is represented by how far along the spoke it is. Lines are then drawn between each of the variables to form a web-like shape.

Within geoscience and petrophysics, we can use radar plots to compare how lithologies vary between wells or display mineralogy variations between rock samples.

Within this tutorial, I will illustrate how we can create a radar plot using some synthetic lithology data. The data represents the average lithologies encountered within a well.

Let’s get started!

To get started, we will need to import two libraries: numpy and matplotlib.

import matplotlib.pyplot as plt
import numpy as np

Next, we can create some dummy data.

Traditionally, this data may already by contained within a pandas dataframe. If it is, then it is recommended to convert the required columns to lists before proceeding.

lithologies = ['Shale', 'Sandstone', 
'Limestone', 'Dolomite',
'Anhydrite', 'Coal', 'Tuff']

well1 = [47, 35, 10, 1, 0, 2, 5]

well2 = [7, 10, 51, 22, 10, 0, 0]

Before we can use the data, we need to ensure that the areas we plot on the radar plot create a closed polygon.

To do this, we need to take all of the elements in the list and then append the first element to the end of the list.

lithologies = [*lithologies, lithologies[0]]
well1 = [*well1, well1[0]]
well2 = [*well2, well2[0]]

If we call upon well2, we will get back the following list of values and we will see that the first number is now also at the end of the list.

[7, 10, 51, 22, 10, 0, 0, 7]

To begin constructing the radar plot, we will first need to sort the positions of the labels from the lithologies list. These will be equally spaced around the edge of the polar plot.

label_loc = np.linspace(start=0, stop=2 * np.pi, num=len(lithologies))

Next, we can move on to creating the radar plot figure.

First, we need to define the figure, which will be created using plt.subplots. Within the subplot_kw parameter, we need to specify that we want a polar plot.

Following that, we will add two axes to the plot and pass in the label_loc variable along with the well1 and well2 lists.

Then, we will create the polar grid using a call to plt.thetagrids() and here, we will pass in the label locations and the lithology labels.

fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

plt.show()

When we run the above code, we will return the following radar plot.

A basic radar plot created with matplotlib. Image by the author.

What we get back looks good for a basic radar plot. However, we can improve it with a few tweaks.

One way we can improve the radar plot is by adding a transparent fill to the two areas.

This is done using ax.fill() and passing in label_loc , the relevant well list containing the values, and setting the opacity to 0.3 using the alpha parameter.

fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

ax.fill(label_loc, well1, alpha=0.3)
ax.fill(label_loc, well2, alpha=0.3)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

plt.show()

When we run the above code, we now have the following radar plot with the areas filled in.

A basic radar plot created with matplotlib showing area fills. Image by the author.

You will notice that the labels in the previous plot look small and overlap the lines.

We can fix this by setting the tick_params and changing the padding and labelsize.

fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

ax.fill(label_loc, well1, alpha=0.3)
ax.fill(label_loc, well2, alpha=0.3)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

ax.tick_params(axis='both', which='major', pad=30, labelsize=15)

plt.show()

We get a plot with much more readable labels when we run the code.

A basic radar plot created with matplotlib showing area fills, and after adjusting the label padding and size. Image by the author.

The previous plot forms a good radar plot that can be used in reports or presentations. However, if we want to stylise it, we can use one of the many matplotlib theme libraries.

If you want to see what libraries are available, then I recommend checking out my previous article, which looks at 4 popular themes.

The cyberpunk theme is one of my favourite themes for creating stylish plots in matplotlib. However, it is purely for aesthetic reasons, and you should always consider your audience and ensure maximum readability.

We can use the cyberpunk theme by importing the library and adding a with statement

import mplcyberpunk

with plt.style.context('cyberpunk'):
fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

ax.fill(label_loc, well1, alpha=0.3)
ax.fill(label_loc, well2, alpha=0.3)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

ax.tick_params(axis='both', which='major', pad=30, labelsize=15)

plt.show()

We can now see that the plot has changed dramatically by adding two lines of code. However, the grid lines are a little faint for my liking.

Matplotlib radar plot after applying a cyberpunk theme. Image by the author.

We can lighten the lines by adding a few additional pieces of code.

Changing the grid lines is done using ax.grid() and setting the color and alpha parameters to white and 0.3, respectively.

In order to add the outer ring for the radar plot, we need to set up a custom tuple containing 4 values: red, green, and blue colour values and an alpha value.

We can then pass this into a call to ax.spines['polar'].set_color()

with plt.style.context('cyberpunk'):
fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

ax.fill(label_loc, well1, alpha=0.3)
ax.fill(label_loc, well2, alpha=0.3)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

ax.tick_params(axis='both', which='major', pad=30, labelsize=15)

ax.spines['polar'].set_linewidth(3)

edge_color = (1, 1, 1, 0.2)
ax.spines['polar'].set_color(edge_color)

ax.grid(color='white', alpha=0.3)

plt.show()

When we run the code, we now have the following radar plot with the radial grid lines. We can play around with the colour and transparency to get the effect we want.

However, bear in mind we do not want to have the lines too bright that they will distract the reader from the main data.

Matplotlib radar plot with cyberpunk theme and visible gridlines. Image by the author.

To finish the styling we can set the grid lines so that they range from and to a number that we want. This will make the outer ring feel more balanced with the rest of the rings.

We can do this by setting the ax.set_ylim() and passing in our min and max values.

with plt.style.context('cyberpunk'):
fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

ax.fill(label_loc, well1, alpha=0.3)
ax.fill(label_loc, well2, alpha=0.3)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

ax.tick_params(axis='both', which='major', pad=30, labelsize=15)

ax.spines['polar'].set_linewidth(3)

edge_color = (1, 1, 1, 0.2)
ax.spines['polar'].set_color(edge_color)

ax.grid(color='white', alpha=0.3)

ax.set_ylim(0, 60)

plt.show()

We now have a much better-looking radar plot.

Matplotlib radar plot with a cyberpunk theme and fixing the range of the rings. Image by the author.

To finish off our plot, we can help the reader understand the plot better, by adding a legend. This will allow the reader to know what area is what.

We could simply add some labels in the ax.plot() calls and then call upon ax.legend, however, this would only add lines to our legend.

If we want to add small rectangles representing the shaded area, we must create some patches first.

This is done by importing Patch from matplotlib.patches.

The created patches are then passed into the ax.legend call.

from matplotlib.patches import Patch

with plt.style.context('cyberpunk'):
fig, ax = plt.subplots(figsize=(10,10), subplot_kw=dict(polar=True))

ax.plot(label_loc, well1, lw=2)
ax.plot(label_loc, well2, lw=2)

ax.fill(label_loc, well1, alpha=0.3)
ax.fill(label_loc, well2, alpha=0.3)

lines, labels = plt.thetagrids(np.degrees(label_loc), labels=lithologies)

ax.tick_params(axis='both', which='major', pad=30, labelsize=15)

ax.spines['polar'].set_linewidth(3)

edge_color = (1, 1, 1, 0.2)
ax.spines['polar'].set_color(edge_color)

ax.grid(color='white', alpha=0.3)

ax.set_ylim(0, 60)

# Create custom legend handles
well1_legend = Patch(facecolor='C0', alpha=0.5, label='Well 1')
well2_legend = Patch(facecolor='C1', alpha=0.5, label='Well 2')

# Add a legend with custom position and handles
ax.legend(handles=[well1_legend, well2_legend],
bbox_to_anchor=(1.3, 0.2), fontsize=20,
frameon=True)

plt.show()

And when we run the code we now have the finished plot.

Matplotlib radar plot with cyberpunk theming. Image by the author.

Radar plots provide a nice data visualisation and can easily be created using matplotlib. With additional style from the Cyberpunk theme library, we can take our radar plot to the next level and make it stylish.

Why don’t you give radar plots a go on your next data visualisation project.

FOLLOW US ON GOOGLE NEWS

Read original article here

Denial of responsibility! Techno Blender is an automatic aggregator of the all world’s media. In each content, the hyperlink to the primary source is specified. All trademarks belong to their rightful owners, all materials to their authors. If you are the owner of the content and do not want us to publish your materials, please contact us by email – [email protected]. The content will be deleted within 24 hours.

Leave a comment