The world’s leading publication for data science, AI, and ML professionals.

Python Data Visualization with Matplotlib – Part 2

Completed Matplotlib tutorials for Python plotting from basic to advanced, with 100+ examples

Figure 1. Various types of plot generated in Matplotlib (Image by Author).
Figure 1. Various types of plot generated in Matplotlib (Image by Author).

Hands-on Tutorials, Introduction to Matplotlib

This story is the next part of Python Data Visualization with Matplotlib – Part 1. In part 1, we have learned how to generate and customize the scatter plot, line plot, histogram, and bar chart. This story will continue the study in Python plotting with Matplotlib concerning generating and customizing box plot, violin plot, pie chart, polar chart, geographic projection, 3D plot, and contour plot.

As in the part 1, I tell you that I have customized the default parameters in Matplotlib. Here is my plotting style

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['text.usetex'] = True
plt.rcParams['font.size'] = 15
plt.rcParams['font.family'] = "serif"
tdir = 'in'
major = 5.0
minor = 3.0
plt.rcParams['xtick.direction'] = tdir
plt.rcParams['ytick.direction'] = tdir
plt.rcParams['xtick.major.size'] = major
plt.rcParams['xtick.minor.size'] = minor
plt.rcParams['ytick.major.size'] = major
plt.rcParams['ytick.minor.size'] = minor

I use LaTeX font for my default in serif family typeface. If you have an error to activate LaTeX font, you need to read [this story](https://towardsdatascience.com/matplotlib-styles-for-scientific-plotting-d023f74515b4) to find the solution. I also customize the xtick and ytick settings changing the tick direction from ‘out’ to ‘in’ tick direction and adjusting the size of the ticks. You can read this story to understand it. Let’s start it.

01. Box plot

Do you know the box plot? Wikipedia defines the box plot as a method for graphically depicting groups of numerical data through their quartiles. It is used in descriptive statistics. You can see an example of a box plot in Figure 1.

Figure 1. Box plot elements (Image by Author / Rizky MN).
Figure 1. Box plot elements (Image by Author / Rizky MN).

In general, the box plot represents the picture of a distribution. It is constructed by a box, the whiskers, and the outliers. In Figure 1, there is no outlier there. In the box element, you can show the median or mean of the distribution. We can see the median in Figure 1. The box is limited by the value of Q1 (first quartile) and Q3 (third quartile). The difference value of Q1 and Q3 is called interquartile (IQR). In default, the whiskers show the boundaries of the distribution, the minimum value, and the maximum value.

Figure 2. Box plot elements (Image by Author / Rizky MN).
Figure 2. Box plot elements (Image by Author / Rizky MN).

In Figure 2, you can see there is an outlier. How can the box plot detect the outliers? An outlier is detected in the box plot when its value is smaller than Q1–1.5 x IQR or larger than Q3+1.5 x IQR.

Before I create a box plot with Matplotlib, I will generate the mock data using this code

N = 50
np.random.seed(100)
box1 = np.random.randn(N) * 2 + 1

To show the variable box1 in the form of a box plot, you can use this code

plt.figure()
plt.boxplot(box1)

You can see the result in Figure 3 when you run the code above

Figure 3. The default box plot in Matplotlib (Image by Author / Rizky MN).
Figure 3. The default box plot in Matplotlib (Image by Author / Rizky MN).

Horizontal box plot

If you want to change the box plot’s orientation horizontally, you need to apply the following argument in the plt.boxplot() code.

vert = False

You can see the horizontal box plot result in Figure 4.

Figure 4. The horizontal box plot in Matplotlib (Image by Author / Rizky MN).
Figure 4. The horizontal box plot in Matplotlib (Image by Author / Rizky MN).

In the next example, I will create a distribution with an outlier by changing the seed number, as shown in the following code

N = 50
np.random.seed(140)
box1 = np.random.randn(N) * 2 + 1
plt.boxplot(box1, vert=False)

If you run the code above, you will get a box plot, as shown in Figure 5.

Figure 5. An outlier in the box plot (Image by Author / Rizky MN).
Figure 5. An outlier in the box plot (Image by Author / Rizky MN).

I will show you how Matplotlib detect the outliers by calculating the value of Q1–1.5 x IQR, Q3+1.5 x IQR, and sorting the distribution using this code

q1 = np.quantile(box1, .25)
q3 = np.quantile(box1, .75)
iqr = q3-q1
lower_boundary = q1 - 1.5 * iqr
upper_boundary = q3 + 1.5 * iqr
sort = np.sort(box1)

To visualize the values I need, I run the following code

If you run the code above, it will show you a figure, as shown in Figure 6.

Figure 6. The explanation of outliers in the box plot (Image by Author / Rizky MN).
Figure 6. The explanation of outliers in the box plot (Image by Author / Rizky MN).

In Figure 6, you can see the random I have generated in red dots. The lower boundary (Q1–1.5 x IQR) equals -3.69, and the minimum value of the distribution is -2.41. So, the left whisker limit in Figure 6 is in the minimum value, -2.41. The upper boundary (Q3 + 1.5 x IQR) is on 5.98, so that the data with value 7.0 is defined as the outlier. The right whisker limit will be ended in 5.47, on the maximum value before the upper boundary. To place the legend on the outside of the figure, you need to read this story.

In the next example, I will show the mean values of the four distributions. I need to create the mock data for four distributions, using this code

np.random.seed(1214)
data = [np.random.normal(0, std, 100) for std in range(10, 14)]

Showing means value

Variable data will generate four normal distribution with mu of 0 and different sigma values for each distribution (10, 11, 12, and 13). To show the means values in the box plot, you need to use this code

plt.boxplot(data, showmeans=True)

If you run the code above, it will generate a box plot, as shown in Figure 7. The green triangle represents the means value for each box plot.

Figure 7. The customized box plots in Matplotlib (Image by Author / Rizky MN).
Figure 7. The customized box plots in Matplotlib (Image by Author / Rizky MN).

You can also show it in the horizontal box plot, using this code

plt.boxplot(data, showmeans=True, vert = False)

The code above will generate a figure, as shown in Figure 8.

Figure 7. Showing the mean values in the horizontal box plot (Image by Author / Rizky MN).
Figure 7. Showing the mean values in the horizontal box plot (Image by Author / Rizky MN).

You can change the symbol of means value by adding this argument

meanline=True

or hide the box shape using this argument

showbox=False

Some customization in the box plot is shown in Figure 8.

Figure 8. Customizing box plots in Matplotlib (Image by Author / Rizky MN).
Figure 8. Customizing box plots in Matplotlib (Image by Author / Rizky MN).

Do you want to change the color of the box? You can do it using this some settings. First, you need to activate the patch artist, as shown in the following code

patch_artist=True

Then, prepare your colors and apply it into the box plot using this code

colors = ['royalblue', 'lightblue', 'lightgreen', 'pink']
for patch, color in zip(box['boxes'], colors):
    patch.set_facecolor(color)

Here is the full code

np.random.seed(123)
all_data = [np.random.normal(0, std, 100) for std in range(10, 14)]
box = plt.boxplot(all_data, notch=False, patch_artist=True)
colors = ['royalblue', 'lightblue', 'lightgreen', 'pink']
for patch, color in zip(box['boxes'], colors):
    patch.set_facecolor(color)
plt.ylim(-50, 50)

The code above will generate a figure, as shown in Figure 9.

Figure 9. Customizing the box plot colors in Matplotlib (Image by Author / Rizky MN).
Figure 9. Customizing the box plot colors in Matplotlib (Image by Author / Rizky MN).

Activate notch

You can show the notch in the box plot, as shown in Figure 10, using this argument

notch=True
Figure 10. Embedding the notch in Matplotlib (Image by Author / Rizky MN).
Figure 10. Embedding the notch in Matplotlib (Image by Author / Rizky MN).

You can reproduce Figure 10 with this code

np.random.seed(123)
all_data = [np.random.normal(0, std, 100) for std in range(10, 14)]
box = plt.boxplot(all_data, notch=True, patch_artist=True)
colors = ['royalblue', 'lightblue', 'lightgreen', 'pink']
for patch, color in zip(box['boxes'], colors):
    patch.set_facecolor(color)
plt.ylim(-50, 50)

02. Violin plot

Violin plot is almost similar visualization with box plot but with no outliers defined. All of the data in the distribution is shown in a kernel function. To create a violin plot, I use this code

N = 50
np.random.seed(140)
viol = np.random.randn(N) * 2 + 1
plt.figure()
plt.violinplot(viol)

The code will show you a violin plot, as shown in Figure 11.

Figure 11. A default violin plot in Matplotlib (Image by Author / Rizky MN).
Figure 11. A default violin plot in Matplotlib (Image by Author / Rizky MN).

To show it horizontally, you can use the same argument in the box plot

vert=False

By default, the violin plot is not showing the median and means value. If you want to show it, you need to insert these arguments

showmeans=True, showmedians=True

If I combine the arguments above and run it, I will be shown a violin plot shown in Figure 12.

Figure 12. A violin plot with median and means value in Matplotlib (Image by Author / Rizky MN).
Figure 12. A violin plot with median and means value in Matplotlib (Image by Author / Rizky MN).

In Figure 12, I think you can not differ where is the median and where is the mean value because they have a similar color. To change the color of each elements in the violin plot such as color of the bars, median value, mean value, minimum value, and maximum value, you need to define the box plot code as a variable, as shown in the following code

violin_parts = plt.violinplot(data, showmedians=True, 
                              showmeans=True)

I generate four different normal distributions and define it as data variable.

To change the color of median, mean, bars, minimum, and maximum value, you can use this code

vmedian = violin_parts['cmedians']
vmedian.set_edgecolor('r')
vmean = violin_parts['cmeans']
vmean.set_edgecolor('k')
vbars = violin_parts['cbars']
vbars.set_edgecolor('k')
vmax = violin_parts['cmaxes']
vmax.set_edgecolor('darkorange')
vmin = violin_parts['cmins']
vmin.set_edgecolor('darkorange')

The customized violin plot is shown in Figure 13.

Figure 13. A customized violin plot in Matplotlib (Image by Author).
Figure 13. A customized violin plot in Matplotlib (Image by Author).

Here is the full code to generate Figure 13.

np.random.seed(1214)
data = [np.random.normal(0, std, 100) for std in range(10, 14)]
plt.figure(figsize = (10, 6))
violin_parts = plt.violinplot(data, showmedians=True, 
                              showmeans=True)
vbars = violin_parts['cbars']
vbars.set_edgecolor('k')
vmedian = violin_parts['cmedians']
vmedian.set_edgecolor('r')
vmean = violin_parts['cmeans']
vmean.set_edgecolor('k')
vmax = violin_parts['cmaxes']
vmax.set_edgecolor('darkorange')
vmin = violin_parts['cmins']
vmin.set_edgecolor('darkorange')

To change the bodies (contour) color, you need to use this code

for vp in violin_parts['bodies']:
    vp.set_facecolor('orange')
    vp.set_edgecolor('k')
    vp.set_linewidth(3)

The code above will change the bodies color to orange with black as the edge color and adjust the line width to 3, as shown in Figure 14.

Figure 14. Customizing the bodies color of violin plot in Matplotlib (Image by Author / Rizky MN).
Figure 14. Customizing the bodies color of violin plot in Matplotlib (Image by Author / Rizky MN).

In Figure 14, I just show the median values for each distribution. You can reproduce Figure 14 with the following code

np.random.seed(1214)
data = [np.random.normal(0, std, 100) for std in range(10, 14)]
plt.figure(figsize = (10, 6))
violin_parts = plt.violinplot(data, widths=0.9, showmedians=True)
for vp in violin_parts['bodies']:
    vp.set_facecolor('orange')
    vp.set_edgecolor('k')
    vp.set_linewidth(3)

I create a full customization of my violin plots, as shown in Figure 15.

Figure 15. Customizing violin plots in Matplotlib (Image by Author / Rizky MN).
Figure 15. Customizing violin plots in Matplotlib (Image by Author / Rizky MN).

You can generate Figure 15 using this code

np.random.seed(1214)
data = [np.random.normal(0, std, 100) for std in range(10, 14)]
# Create violin plot objects:
plt.figure(figsize=(10, 6))
violin_parts=plt.violinplot(data, showmedians=True, showmeans=True)
# Make the violin body blue with a red border:
for vp in violin_parts['bodies']:
    vp.set_facecolor('royalblue')
    vp.set_edgecolor('k')
    vp.set_linewidth(2)
    vp.set_alpha(.8)
colors = ['k', 'red', 'red', 'w', 'k']
part = ['cbars','cmins','cmaxes','cmeans','cmedians']
for i in range(len(part)):
    vp = violin_parts[part[i]]
    vp.set_edgecolor(colors[i])
    vp.set_linewidth(2)

03. Pie chart

Before generating a pie chart, I create data on the numbers of some animals using this code

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
numbers = [15, 30, 45, 10]

To visualize it in a pie chart, you can use this code

plt.pie(numbers)

To code above will generate a pie chart, as shown in Figure 16.

Figure 16. A default pie chart in Matplotlib (Image by Author / Rizky MN).
Figure 16. A default pie chart in Matplotlib (Image by Author / Rizky MN).

Figure 16 shows a simple pie chart. You can give the labels for each animal data, using this argument

labels = labels

If you want to show the number of each animal, you need to insert this argument

autopct='%1.1f%%'

You can see the result of your pie chart after adding labels and numbers in Figure 17.

Figure 17. Customize a pie chart in Matplotlib (Image by Author / Rizky MN).
Figure 17. Customize a pie chart in Matplotlib (Image by Author / Rizky MN).

Here is the full code to create Figure 17.

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]
plt.figure()
plt.pie(sizes, labels = labels, autopct='%1.1f%%')

You can change the starting angle for your pie chart using this argument

startangle=90

The default starting angle is 0, applied for the first data (Frogs). I customize the starting angle in two different angles, as shown in Figure 18.

Figure 18. Customizing the starting angle of a pie chart in Matplotlib (Image by Author / Rizky MN).
Figure 18. Customizing the starting angle of a pie chart in Matplotlib (Image by Author / Rizky MN).

Here is the code to generate Figure 18

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]
explode1 = (0, 0.1, 0, 0)
explode2 = (0, 0, 0.1, 0)
plt.figure(figsize=(10, 10))
plt.subplot(121)
plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)
plt.title('Startangle = 90$^circ$')
plt.subplot(122)
plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=180)
plt.title('Startangle = 180$^circ$')

You can also make a margin for a specific pie chart, as shown in Figure 19.

Figure 19. Customizing pie chart explode in Matplotlib (Image by Author / Rizky MN).
Figure 19. Customizing pie chart explode in Matplotlib (Image by Author / Rizky MN).

You can reproduce Figure 19 using the following code

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]
explode1 = (0, 0.1, 0, 0)
explode2 = (0, 0, 0.1, 0)
plt.figure(figsize=(10, 10))
plt.subplot(121)
plt.pie(sizes, explode=explode1, labels=labels, 
        autopct='%1.1f%%', startangle=90)
plt.subplot(122)
plt.pie(sizes, explode=explode2, labels=labels, 
        autopct='%1.1f%%', startangle=180)

You can change the margin by adjusting the value in the variable explode.

Applying different styles in the pie chart

Do you want to visualize your data in a pie chart with a different style? Yups, you can see Figure 20.

Figure 20. Applying a different style in the pie chart Matplotlib (Image by Author / Rizky MN).
Figure 20. Applying a different style in the pie chart Matplotlib (Image by Author / Rizky MN).

The difference with the previous pie chart is I place the labels in the legend. To do it, you need to use this argument

textprops={'color':"w"}

and this code

plt.legend(labels, bbox_to_anchor = (1., .95),  title="Labels Name")

You can reproduce Figure 20 using the following code

labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]
explode = (0, 0.05, 0, 0)
plt.figure(figsize=(7, 7))
plt.pie(sizes, autopct='%1.1f%%', textprops={'color':"w"}, 
        explode = explode, startangle = 90)

Shadow in a pie chart

You can add a shadow in your pie chart using this argument

shadow=True

The result is shown in Figure 21.

Figure 21. Adding the shadow in a pie chart in Matplotlib (Image by Author / Rizky MN).
Figure 21. Adding the shadow in a pie chart in Matplotlib (Image by Author / Rizky MN).

I think I know what you are thinking about :D. The shadow is ugly, right? I have tried many alternatives for it; here are they

a. If you are using Jupyter, you can save your pie chart manually by right-clicking the figure. Then, click Save Image As, as shown in Figure 22.

Figure 22. Saving image manually in Jupyter (Image by Author / Rizky MN).
Figure 22. Saving image manually in Jupyter (Image by Author / Rizky MN).

The saved image is shown in Figure 23.

Figure 23. The alternative saving image in Jupyter and Matplotlib (Image by Author / Rizky MN).
Figure 23. The alternative saving image in Jupyter and Matplotlib (Image by Author / Rizky MN).

b. The other alternative is adding the white stroke as the foreground. To apply it, you need to import path_effects from Matplotlib using this code

import matplotlib.patheffects as path_effects

Then, define the variable name for your pie chart, as shown in the following code

patches, texts, autotexts = plt.pie(sizes, autopct='%1.1f%%', 
                                    textprops={'color':"w"}, 
                                    explode = explode, 
                                    startangle = 90, shadow=True)

Next, customize the path_effects with this code

for patch in patches:
    patch.set_path_effects([path_effects.Stroke(linewidth=2.5, 
                                                foreground = 'w')])

Here is the full code

If you run the code above, it will create a pie chart, as shown in Figure 24.

Figure 24. Adding the foreground stroke in a pie chart Matplotlib (Image by Author / Rizky MN).
Figure 24. Adding the foreground stroke in a pie chart Matplotlib (Image by Author / Rizky MN).

It is not perfect, but I think it is prettier than without adding a stroke. You can also combine the first and the second alternatives and get a pie chart shown in Figure 25.

Figure 25. Customizing shadow in a pie chart Matplotlib (Image by Author / Rizky MN).
Figure 25. Customizing shadow in a pie chart Matplotlib (Image by Author / Rizky MN).

Doughnut chart

From the pie chart features in Matplotlib, you can create a doughnut chart, as shown in Figure 26.

Figure 26. A simple doughnut chart in Matplotlib (Image by Author / Rizky MN).
Figure 26. A simple doughnut chart in Matplotlib (Image by Author / Rizky MN).

Here is the code to generate the data for Figure 26.

size = 0.3
vals = np.array([[60.], [37.], [29.]])
cmap = plt.get_cmap("tab20c")
outer_colors = cmap(np.arange(3)*4)
inner_colors = cmap(np.array([1, 2, 5, 6, 9, 10]))

Doughnut chart is similar with the pie chart but without full radius from the center. In Figure 26, I set the radius equals 0.3. Here is the code to generate Figure 26.

plt.figure(figsize=(10,10))
plt.pie(vals.sum(axis=1), radius=1, colors=outer_colors,
       wedgeprops=dict(width=size, edgecolor='w'))

I also create two different radius sizes, as shown in Figure 27.

Figure 27. Two different radius sizes in the doughnut chart Matplotlib (Image by Author / Rizky MN).
Figure 27. Two different radius sizes in the doughnut chart Matplotlib (Image by Author / Rizky MN).

You can reproduce Figure 27 with the following code.

vals = np.array([[60.], [37.], [29.]])
plt.figure(figsize=(10,10))
plt.subplot(121)
plt.pie(vals.sum(axis=1), radius=1, colors=outer_colors,
       wedgeprops=dict(width=.3, edgecolor='w'))
plt.title('Size = 0.3')
plt.subplot(122)
plt.pie(vals.sum(axis=1), radius=1, colors=outer_colors,
       wedgeprops=dict(width=.5, edgecolor='w'))
plt.title('Size = 0.5')

You can also create a double doughnut chart, as shown in Figure 28.

Figure 28. A double doughnut chart in Matplotlib (Image by Author / Rizky MN).
Figure 28. A double doughnut chart in Matplotlib (Image by Author / Rizky MN).

Here is the code to generate Figure 28.

plt.figure(figsize=(10, 10))
size = 0.3
vals = np.array([[60., 32.], [37., 40.], [29., 10.]])
cmap = plt.get_cmap("tab20c")
outer_colors = cmap(np.arange(3)*4)
inner_colors = cmap(np.array([1, 2, 5, 6, 9, 10]))
plt.pie(vals.sum(axis=1), radius=1, colors=outer_colors,
       wedgeprops=dict(width=size, edgecolor='w'))
plt.pie(vals.flatten(), radius=1-size, colors=inner_colors,
       wedgeprops=dict(width=size, edgecolor='w'))

If you read the documentation of doughnut chart in Matplotlib site, you will meet a nice doughnut chart, as shown in Figure 29.

Figure 29. A nice doughnut chart in Matplotlib (Image by Author / Rizky MN).
Figure 29. A nice doughnut chart in Matplotlib (Image by Author / Rizky MN).

You can create Figure 29 using this code.

04. Polar chart

In planar projection, you will have an x-axis and y-axis. In polar projection, you need to define it in the form of radius and angle, as shown in Figure 30.

Figure 30. A comparison of polar projection and planar projection (Image by Author / Rizky MN).
Figure 30. A comparison of polar projection and planar projection (Image by Author / Rizky MN).

In polar projection, the radius axis is shown in the size of circle radius and the angle is projected as the angle of each circle with 0 degree is the starting point. To generate a polar projection, you need to define the projection type as polar, as shown in the following argument.

projection='polar'

Here is the full code to generate Figure 30.

r = np.linspace(0, 2, 100)
theta = 2 * np.pi * r
fig = plt.figure(figsize=(13, 4))
ax1 = plt.subplot(121, projection='polar')
ax1.scatter(theta, r, label = 'Polar Projection', s = 10)
ax1.legend(bbox_to_anchor = (.85, 1.35))
ax2 = plt.subplot(122)
ax2.scatter(theta, r, label = 'Planar Projection', s = 10)
ax2.legend(bbox_to_anchor = (0.85, 1.35))
ax2.set_xlabel('R')
ax2.set_ylabel(r'$theta$')

You can also present your data in plot line styles in the polar projection, as shown in Figure 31.

Figure 31. Creating a plotline in the polar projection (Image by Author / Rizky MN).
Figure 31. Creating a plotline in the polar projection (Image by Author / Rizky MN).

You can reproduce Figure 31 with this code

Next is creating a bar chart in the polar projection, as shown in Figure 32.

Figure 32. A bar chart in the polar projection (Image by Author / Rizky MN).
Figure 32. A bar chart in the polar projection (Image by Author / Rizky MN).

When you see Figure 32, maybe you are remembering the logo of Matplotlib 😀 To create Figure 32, you need to generate the data, using this code

np.random.seed(10130)
N = 20
theta = np.linspace(0.0, 2 * np.pi, N, endpoint=False)
radii = 10 * np.random.rand(N)
width = np.random.rand(N) * .8 - .1
colors = plt.cm.Spectral(radii / 10)

To visualize it, you can use the following code

plt.figure(figsize=(7, 7))
ax = plt.subplot(111, projection='polar')
ax.bar(theta, radii, width=width, bottom=0.0, 
       color=colors, alpha=0.5)

If you are intersted in generating Matplotlib logo using the polar bar chart, you can read this documentation.

Matplotlib logo – Matplotlib 3.1.0 documentation

05. Geographic projection

To visualize your geographical data, you can use geographical projection provided by Matplotlib. There are four types of projections: Aitoff, Hammer, Mollweide, and Lambert projection. To understand it, I will create a mock data using this code

N = 100
np.random.seed(157)
long = np.random.random(N) * 360 - 180
lat = np.random.random(N) * 180 - 90

To visualize it in the Aitoff projection, you can use this code

plt.figure(figsize=(12, 7))
plt.subplot(111, projection="aitoff")
plt.scatter(long, lat, marker = '*', color = 'red', s = 40)
plt.title("Aitoff")
plt.grid(True)

The code will show you a figure, as shown in Figure 33.

Figure 33. Aitoff projection in Matplotlib (Image by Author / Rizky MN).
Figure 33. Aitoff projection in Matplotlib (Image by Author / Rizky MN).

In Aitoff projection, you need to ensure your data is in the unit of degree.

Next is Hammer projection. You can present your data in the Hammer projection using this code

plt.figure(figsize=(12, 7))
plt.subplot(111, projection="hammer")
plt.scatter(long, lat, marker = '*', color = 'red', s = 40)
plt.title("Hammer")
plt.grid(True)

The unit of long and lat variable shown in Hammer projection is in the degree. The code above will generate a figure, as shown in Figure 34.

Figure 34. Hammer projection in Matplotlib (Image by Author / Rizky MN).
Figure 34. Hammer projection in Matplotlib (Image by Author / Rizky MN).

I am not sure what are the differences between Aitoff and Hammer projection. If you need some explanation, you can read these links.

Aitoff projection

Hammer projection

In Mollweide projection, the unit of the data needs to be converted in the radians. Here is the code to generate the data in radians.

N = 100
np.random.seed(157)
long = np.random.random(N) * 2 * np.pi  - np.pi
lat = np.random.random(N) * np.pi - (np.pi / 2)

To visualize it in the Mollweide projection, you can use this code

plt.figure(figsize=(12, 7))
plt.subplot(111, projection="mollweide")
plt.scatter(long, lat, marker = '*', color = 'red', s = 40)
plt.title("Mollweide")
plt.grid(True)

If you run the code above, it will create a figure, as shown in Figure 35.

Figure 35. Mollweide projection in Matplotlib (Image by Author / Rizky MN).
Figure 35. Mollweide projection in Matplotlib (Image by Author / Rizky MN).

The last projection is the Lambert projection, as shown in Figure 36.

Figure 36. Lambert projection in Matplotlib (Image by Author / Rizky MN).
Figure 36. Lambert projection in Matplotlib (Image by Author / Rizky MN).

The unit of the data is in the radians. You can reproduce Figure 36 using this code.

N = 100
np.random.seed(157)
long = np.random.random(N) * 2 * np.pi  - np.pi
lat = np.random.random(N) * np.pi - (np.pi / 2)
plt.figure(figsize=(12, 12))
plt.subplot(111, projection="lambert")
plt.scatter(long, lat, marker = '*', color = 'red', s = 40)
plt.title("Lambert")
plt.grid(True)

06. 3D plot

To create a 3D plot, you need to define the projection type as 3d, as shown in the following argument

projection = '3d'

The 3D projection will give you a result shown in Figure 37.

Figure 37. 3D projection in Matplotlib (Image by Author / Rizky MN).
Figure 37. 3D projection in Matplotlib (Image by Author / Rizky MN).

I generate the mock data with this code.

N = 250
np.random.seed(124)
x = 15 * np.random.random(N)
y = np.sin(x) + 0.25 * np.random.random(N)
z = np.cos(x) + 0.25 * np.random.random(N)

To visualize the data in the 3D scatter plot, you can use this code.

plt.figure(figsize=(9, 6))
ax = plt.axes(projection = '3d')
ax.scatter3D(x, y, z, color = 'r')
ax.set_xlabel('x', fontsize = 20, labelpad = 20)
ax.set_ylabel('y', fontsize = 20, labelpad = 20)
ax.set_zlabel('z', fontsize = 20, labelpad = 20)

The code will generate a 3d plot, as shown in Figure 38.

Figure 38. 3D scatter plot in Matplotlib (Image by Author / Rizky MN).
Figure 38. 3D scatter plot in Matplotlib (Image by Author / Rizky MN).

As I know, in the newest Matplotlib version, the aspect is always equal for each axis. To change it, you can use this code

ax.set_box_aspect((2., 1.5, 1.2))

I change the aspect ratio for the x-, y-, and z-axis to 2:1.5:1.2. After applying the code above, you will have a plot, as shown in Figure 39.

Figure 39. Customizing the aspect in a 3D scatter plot in Matplotlib (Image by Author / Rizky MN).
Figure 39. Customizing the aspect in a 3D scatter plot in Matplotlib (Image by Author / Rizky MN).

3D plotline

You can create a 3D plotline, as shown in Figure 40.

Figure 40. The 3D plotline in Matplotlib (Image by Author / Rizky MN).
Figure 40. The 3D plotline in Matplotlib (Image by Author / Rizky MN).

You can reproduce Figure 40 with this code.

N = 100
np.random.seed(124)
xline = np.linspace(0, 15, N)
yline = np.sin(xline) 
zline = np.cos(xline)
fig = plt.figure(figsize=(9, 6))
ax = plt.axes(projection = '3d')
ax.plot3D(xline, yline, zline)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.set_box_aspect((2, 1.5, 1.2))

You can change the view angle with this code

ax.view_init(10, 180)

The first argument in the view_init is the elevation angle and the second one is for azimuthal angle. You can see the different representation for different angles, as shown in Figure 41.

Figure 41. Customizing the view angle in the 3D plot (Image by Author / Rizky MN).
Figure 41. Customizing the view angle in the 3D plot (Image by Author / Rizky MN).

Triangular 3D surfaces

To generate a triangular 3D surfaces in Matplotlib, you can use this code.

ax.plot_trisurf()

I generate the data to be visualized in the triangular 3D surfaces with this code

N = 2000
np.random.seed(124)
r = 2 * np.pi * np.random.random(N)
theta = 20 * np.pi * np.random.random(N)
xdata = np.ravel(r * np.sin(theta))
ydata = np.ravel(r * np.cos(theta))
zdata = np.sin(xdata) + np.cos(ydata)

You can see the triangular 3D surfaces plot from the data above in Figure 42.

Figure 42. The triangular 3D surfaces plot in Matplotlib (Image by Author / Rizky MN).
Figure 42. The triangular 3D surfaces plot in Matplotlib (Image by Author / Rizky MN).

You can reproduce Figure 42 with this code

3D contour plot

Matplotlib provides a 3D contour plot. You can create it using this code

ax.contour3D()

I generate the mock data using the following code

N = 100
np.random.seed(3124)
x = np.linspace(-2, 2, N) + np.random.random(N)
y = np.linspace(-2, 2, N) + np.random.random(N)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)

To visualize it, I run this code

fig = plt.figure(figsize=(9, 6))
ax = plt.axes(projection = '3d')
ax.contour3D(X, Y, Z, cmap = 'Spectral')

After customization, my 3D contour plot is shown in Figure 43.

Figure 43. A default 3D contour plot in Matplotlib (Image by Author / Rizky MN).
Figure 43. A default 3D contour plot in Matplotlib (Image by Author / Rizky MN).

You can reproduce Figure 43 using this code

By default, Matplotlib generates a 3D contour plot in the contour of 7 counts. You can change it by writing down the counts you want in the fourth argument of ax.contour3D(), as shown in the code below

ax.contour3D(X, Y, Z, 256, cmap = 'Spectral')

You can see the different 3D contour plots in Figure 44.

Figure 44. Customizing 3D contour plot in Matplotlib (Image by Author / Rizky MN).
Figure 44. Customizing 3D contour plot in Matplotlib (Image by Author / Rizky MN).

Here is the full code to generate Figure 44.

To show the color bar, you can use this code

plt.colorbar()

The argument needed is your 3D contour plot. So, it would be best if you defined your plot into a variable. In my code, it is defined as variable p.

You can use the same code applied in the previous plots to change the view angle, as shown in Figure 45.

Figure 45. Customizing 3D contour plot with color bar in Matplotlib (Image by Author / Rizky MN).
Figure 45. Customizing 3D contour plot with color bar in Matplotlib (Image by Author / Rizky MN).

Bugs in 3D contour Matplotlib

I think there is a bug in Matplotlib 3D contour, as shown in Figure 46.

Figure 46. A bug in 3D contour Matplotlib (Image by Author / Rizky MN).
Figure 46. A bug in 3D contour Matplotlib (Image by Author / Rizky MN).

To create Figure 46, you change the value of elevation and azimuth angle in the previous code (code to create Figure 45). Did you get what I mean by the bugs? If you analyze Figure 46 carefully, you will get a strange feature. You can see it in Figure 47.

Figure 47. A bug in 3D contour Matplotlib (Image by Author / Rizky MN).
Figure 47. A bug in 3D contour Matplotlib (Image by Author / Rizky MN).

The area covered by the blue line is not in the right place. We should not see it because it is placed at the back. I am not sure it is a bug or not, but I think it needs to be repaired by Matplotlib.

To understand it in more detail, I introduce two different contour representations in Matplotlib, ax.contour() and ax.contourf(), as shown in Figure 48.

Figure 48. Two different representation of 3D contour plots in Matplotlib (Image by Author / Rizky MN).
Figure 48. Two different representation of 3D contour plots in Matplotlib (Image by Author / Rizky MN).

contourf in ax.contourf means filled contour. So, you can see the difference between ax.contour() and ax.contourf() in Figure 48. ax.contour has similar default contour counts with ax.contour3D(), 7 counts. But, ax.contourf() has different counts, it is 8. You can reproduce Figure 48 with this code

N = 100
np.random.seed(3124)
x = np.linspace(-2, 2, N) + np.random.random(N)
y = np.linspace(-2, 2, N) + np.random.random(N)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
plt.figure(figsize=(14, 6))
ax1 = plt.subplot(121, projection = '3d')
ax1.contour(X, Y, Z, cmap = 'Spectral')
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.set_zlabel('z')
ax1.set_box_aspect((3, 3, 1))
ax1.view_init(10, 100)
ax1.set_title('Contour Default, elevation = 10, azimuth = 100')
ax2 = plt.subplot(122, projection = '3d')
ax2.contourf(X, Y, Z, cmap = 'Spectral')
ax2.set_xlabel('x')
ax2.set_ylabel('y')
ax2.set_zlabel('z')
ax2.set_box_aspect((3, 3, 1))
ax2.view_init(10, 100)
ax2.set_title('Contourf Default, elevation = 10, azimuth = 100')

You can observe carefully in the right panel Figure 48 (contourf plot). The bugs I mentioned in 3D contour is not detected. You can see it more detail in Figure 49.

Figure 49. The comparison of ax.contur() and ax.contourf() in detecting the Matplotlib's bug (Image by Author / Rizky MN).
Figure 49. The comparison of ax.contur() and ax.contourf() in detecting the Matplotlib’s bug (Image by Author / Rizky MN).

You can see that if ax.contour() will give you the same error but not for ax.contourf(). So, I recommend you to use ax.contourf() if you want to visualize contour plot in 3D projection.

Wireframe plot

You can generate a wireframe plot in Matplotlib using this code

ax.plot_wireframe()

Here is the code to generate the mock data to be visualized in the wireframe plot

N = 100
np.random.seed(3124)
x = np.linspace(-2, 2, N) + np.random.random(N)
y = np.linspace(-2, 2, N) + np.random.random(N)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)

The default wireframe plot as shown in Figure 50.

Figure 50. A default wireframe plot in Matplotlib (Image by Author / Rizky MN).
Figure 50. A default wireframe plot in Matplotlib (Image by Author / Rizky MN).

You can reproduce Figure 50 with the following code

N = 100
np.random.seed(3124)
x = np.linspace(-2, 2, N) + np.random.random(N)
y = np.linspace(-2, 2, N) + np.random.random(N)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
fig = plt.figure(figsize=(10, 10))
ax = plt.axes(projection = '3d')
ax.plot_wireframe(X, Y, Z, color = 'k', alpha = .2)

The customized wireframe plot is shown in Figure 51.

Figure 51. A customized wireframe plot in Matplotlib (Image by Author / Rizky MN).
Figure 51. A customized wireframe plot in Matplotlib (Image by Author / Rizky MN).

I change the number of wireframe layer to 5, set the elevation angle to 60 degrees and the azimuth angle to 100 degrees. You can use this code to generate Figure 51.

N = 100
np.random.seed(3124)
x = np.linspace(-2, 2, N) + np.random.random(N)
y = np.linspace(-2, 2, N) + np.random.random(N)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
fig = plt.figure(figsize=(9, 6))
ax = plt.axes(projection = '3d')# 3d contour plot
ax.plot_wireframe(X, Y, Z, 5, color = 'k', alpha = .2)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.set_box_aspect((2, 2, 1))
ax.view_init(60, 100)
ax.set_title('Wireframe counts = 5, elevation = 60, azimuth = 100')

If you want to check whereas we meet the similar bugs in ax.contour() and ax.contour3D() or not, you can change the elevation angle to 10 degrees and the azimuth angle to 100 degrees, as shown in Figure 52.

Figure 52. A customized wireframe plot in Matplotlib (Image by Author / Rizky MN).
Figure 52. A customized wireframe plot in Matplotlib (Image by Author / Rizky MN).

We do not meet the bugs in the wireframe plot.

3D surface plot

You can generate a 3D surface plot in Matplotlib with this code.

ax.plot_surface()

The customized 3D surface plot is shown in Figure 53.

Figure 53. A customized 3D surface plot in Matplotlib (Image by Author / Rizky MN).
Figure 53. A customized 3D surface plot in Matplotlib (Image by Author / Rizky MN).

You can reproduce Figure 53 with this code

N = 100
np.random.seed(3124)
x = np.linspace(-2, 2, N) + np.random.random(N)
y = np.linspace(-2, 2, N) + np.random.random(N)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
fig = plt.figure(figsize=(8, 8))
ax = plt.axes(projection = '3d')# 3d contour plot
ax.plot_surface(X, Y, Z, )
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.set_box_aspect((2, 2, 1))
ax.view_init(10, 100)
ax.set_title('Plot surface Default, elevation = 10, azimuth = 100')

You can the values for cstride and rstride using this argument

rstride = 1, cstride = 1

You can see the difference between the default cstride and rstride value to the customized one in Figure 54.

Figure 54. The customized 3D surface plot in Matplotlib (Image by Author / Rizky MN).
Figure 54. The customized 3D surface plot in Matplotlib (Image by Author / Rizky MN).

To generate Figure 54, you can use this code

You will not meet the bugs you meet in the contour plot, as shown in Figure 55.

Figure 55. Checking the bugs in the 3D surface plot in Matplotlib (Image by Author / Rizky MN).
Figure 55. Checking the bugs in the 3D surface plot in Matplotlib (Image by Author / Rizky MN).

Creating a ball in Matplotlib

You can create a ball in Matplotlib, as shown in Figure 56.

Figure 56. Creating a ball in Matplotlib (Image by Author / Rizky MN).
Figure 56. Creating a ball in Matplotlib (Image by Author / Rizky MN).

You can create Figure 56 with the following code

u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = 10 * np.outer(np.cos(u), np.sin(v))
y = 10 * np.outer(np.sin(u), np.sin(v))
z = 10 * np.outer(np.ones(np.size(u)), np.cos(v))
plt.figure(figsize=(10, 10))
ax = plt.subplot(projection = '3d')
ax.plot_surface(x, y, z, cmap = 'inferno')

You can customize the view angle for it, as shown in Figure 57.

Figure 57. Customizing the ball in Matplotlib (Image by Author / Rizky MN).
Figure 57. Customizing the ball in Matplotlib (Image by Author / Rizky MN).

You can reproduce Figure 57 using this code

07. 2D Contour plot

The last plot type I will show you is the 2D contour plot. You can generate a 2D contour plot using this code

plt.contour()

Although the name is 2D contour plot, but it shows the 3D data. I create the mock data using this code

N = 100
np.random.seed(100)
x = np.linspace(-2, 2, N) + np.random.random(N)
y = np.linspace(-2, 2, N) + np.random.random(N)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)

I present the mock data into a contour plot, as shown in Figure 58.

Figure 58. A default 2D contour plot in Matplotlib (Image by Author / Rizky MN).
Figure 58. A default 2D contour plot in Matplotlib (Image by Author / Rizky MN).

You can reproduce Figure 58 with the following code

N = 100
np.random.seed(100)
x = np.linspace(-2, 2, N) + np.random.random(N)
y = np.linspace(-2, 2, N) + np.random.random(N)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
plt.figure(figsize=(7, 5))
plt.contour(X, Y, Z)
plt.title('Contour 2D Default', pad = 10)

I generate two customized contour plots, as shown in Figure 59.

Figure 59. Two customized 2D contour plots in Matplotlib (Image by Author / Rizky MN).
Figure 59. Two customized 2D contour plots in Matplotlib (Image by Author / Rizky MN).

To create Figure 59, you can use this code

N = 100
np.random.seed(100)
x = np.linspace(-2, 2, N) + np.random.random(N)
y = np.linspace(-2, 2, N) + np.random.random(N)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)
plt.figure(figsize=(15, 5))
plt.subplot(121)
plt.contour(X, Y, Z, 256)
plt.title('Contour 2D counts = 256, cmap = viridis', pad = 10)
plt.colorbar()
plt.subplot(122)
plt.contour(X, Y, Z, 256, cmap = 'Spectral')
plt.colorbar()
plt.title('Contour 2D counts = 256, cmap = Spectral', pad = 10)

Also, you can generate contour filled into 2D projection, as shown in Figure 60.

Figure 60. A default contouf plot in Matplotlib (Image by Author / Rizky MN).
Figure 60. A default contouf plot in Matplotlib (Image by Author / Rizky MN).

You can generate Figure 60 with the following code

N = 100
np.random.seed(100)
x = np.linspace(-2, 2, N) + np.random.random(N)
y = np.linspace(-2, 2, N) + np.random.random(N)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)**3
plt.figure(figsize=(7, 5))
plt.contourf(X, Y, Z, cmap = 'Spectral')
plt.colorbar()
plt.title('Contourf 2D Default', pad = 10)

Here I generate two different contourf plots, as shown in Figure 61.

Figure 61. Two customized confourf plot in Matplotlib (Image by Author / Rizky MN).
Figure 61. Two customized confourf plot in Matplotlib (Image by Author / Rizky MN).

You can generate Figure 61 using this code

N = 100
np.random.seed(100)
x = np.linspace(-2, 2, N) + np.random.random(N)
y = np.linspace(-2, 2, N) + np.random.random(N)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) + np.cos(Y)**3
plt.figure(figsize=(15, 5))
plt.subplot(121)
plt.contourf(X, Y, Z, 50, cmap = 'inferno')
plt.colorbar()
plt.title('Contourf 2D counts = 50', pad = 10)
plt.subplot(122)
plt.contourf(X, Y, Z, 200, cmap = 'inferno')
plt.colorbar()
plt.title('Contourf 2D counts = 200', pad = 10)

Conclusion

Data visualization is significant in analyzing data from small data or Big Data in the technological era. We need it to have a global picture of our data. Various types of visualization you can use with Matplotlib. This is just a small part of python plotting with Matplotlib. In this Matplotlib guideline series (part 1 and part 2), I have generated 101 figures. If you read all of the part, you need to spend your 48 minutes 😀 I hope this story can help you to visualize your data into various plot types.

If you liked this article, here are some other articles you may enjoy:

5 Powerful Tricks to Visualize Your Data with Matplotlib

Matplotlib Styles for Scientific Plotting

Creating Colormaps in Matplotlib

Customizing Multiple Subplots in Matplotlib

Introduction to Big Data with Vaex – A Simple Code to Read 1.25 Billion Rows

That’s all. Thanks for reading this story. Comment and share if you like it. I also recommend you follow my account to get a notification when I post my new story.


Related Articles