bar_plot_with_error_bars

Engineers collect data and make conclusions based on the results. An important way to view results is with statistical charts. In this post we will build a bar chart to compare the tensile strength of 3D-printed ABS plastic compared to the tensile strength of 3D-printed HIPS plastic. We will add error bars to the chart to show the amount of uncertainty in the data. In the bar plot we construct, the height of the bars will represent the mean or average tensile stength. One bar will represent the average strength of ABS and the other bar will show the average strength of HIPS. We will then add error bars to the plot which will represent +1/-1 standard deviation about the mean.

We will use Python, the statistics module (part of the Python standard library), and matplotlib to build the bar plot. I recommend that undergraduate engineers use the Anaconda distribution of Python, which comes with matplotlib already installed. For help installing Anaconda, see a previous blog post: Installing Anaconda on Windows 10. If matplotlib is not available in your version of Python, open a terminal or the Anaconda Prompt and type:

$ pip install matplotlib

or

> conda install matplotlib

The data we are going to plot is from the tensile testing of two different kinds of 3D-printed plastic, ABS and HIPS (HIPS stands for High Impact Polystyrene). You can download the data using the link below:

3D-printed-tensile-bar-data.xlsx

I'm constructing the plot in a jupyter notebook. You could also build the code in a .py file and run the code to produce the plot.

A note about using matplotlib on MacOSX: if you recieve an error message that matplotlib is not installed as a framework, consider using the Anaconda distribution of Python and running the code in a jupyter notebook.

To open a new jupyter notebook go to the Anaconda Prompt or a terminal and type:

> jupyter notebook

Alternativly, you can start a new jupyter notebook by cliking the Windows start button and searching for [Anaconda3] --> [Jupyter Notebook]

If jupyter is not installed on your system, you can install it using the Anaconda Prompt or use a terminal and pip:

> conda install jupyter

or

$ pip install jupyter

At the top of the jupyter notebook (or .py file), we need to import the required packages:

  • statistics (part of the Python standard library, but still needs to be imported) and
  • matplotlib

From the statistics module we will import two functions: mean (average) and stdev(standard deviation). If we use this import line:

from statistics import mean, stdev

We can use the names mean() and stdev() in our code. However, if we use a more general import line:

import statistics

Then we will need to call statistics.mean() and statistics.stdev() in our code.

matplotlib also needs to be imported. The typical way to do this is with the line:

import matplotlib.pyplot as plt

Then thoughout our code, we can use plt() instead of writing out matplotlib.pyplot() each time we want to use a matplotlib method.

The %matplotlib inline magic command is added so that we can see our plot right in the jupyter notebook. If you build the plot in a .py file, the %matplotlib inline command should be left out as it will return an error.

In [1]:
# import packages
from statistics import mean, stdev
import matplotlib.pyplot as plt
#include if using a jupyter notebook, remove if using a .py file
%matplotlib inline                

Create two variables which contains the data for ABS and HIPS as a list of individual tensile strength values.

After the import lines, we need to create two variables: one variable for the ABS data and one variable for HIPS data. We will assign the data points as a list of numbers saved in two variables. The general format to create a list in Python is to use list_name = [item1, item2, item3] with square brackets on the outside and commas between the items. The items for the two lists came from the .xlsx file that contains the data (3D-printed-tensile-bar-data.xlsx). The tensile strength is in column [F] labeled [Tensile Strength (Mpa)]. Rows 2-17 contain data for ABS and rows 18-37 contain data for HIPS.

In [2]:
# data
ABS = [18.6, 21.6 ,22, 21, 18, 20.9, 21, 19.3, 18.8, 20, 19.4, 16, 23.8, 19.3, 19.7, 19.5]
HIPS = [10.4, 4.9, 10.2, 10.5, 10.9, 12.9, 11.8, 8.4, 10, 10.6, 8.6, 9.7, 10.8, 10.7, 11, 12.4, 13.3, 11.4, 14.8, 13.5]

Find the mean and standard deviation for each set of data

We'll use the mean() and stdev() functions from the statistics module to find the mean (or average) and standard deviation of the two data sets. A summary of these two functions is below:

statistics module function description
mean() calculate the mean or average of a list of numubers
stdev() calculate the standard deviation of a list of numbers
In [3]:
# find the mean using the mean() function from the statistics library
ABS_mean = mean(ABS)
HIPS_mean = mean(HIPS)

# find the standard deviation using the stdev() function from the statistics library
ABS_stdev = stdev(ABS)
HIPS_stdev = stdev(HIPS)

Build a simple bar plot

Matplotlib's bar plot fuction can be accessed using plt.bar(). We need to include at least two arguments as shown below:

plt.bar (['list', 'of' ,'bar', 'labels'], [list, of, bar, heights])

We will pass in ['ABS', 'HIPS'] for our list of bar labels, and [ABS_mean, HIPS_mean] for our list of bar heights. The command plt.show() will show the plot in a jupyter notebook or show the plot in a new window if running a .py file.

In [4]:
# Build a bar plot
plt.bar(['ABS', 'HIPS'],[ABS_mean, HIPS_mean])
plt.show()

Add axis labels and title

The plot looks pretty good, but we should add axis labels (with units) and a title to our plot. We can add the axis labels and titles with plt.xlabel(), plt.ylabel() and plt.title(). We need to pass in strings enclosed in quotes ' ' with these methods. A summary of the matplotlib functions is below:

matplotlib function description
plt.bar() build a bar plot
plt.xlabel() x-axis label
plt.ylabel() y-axis label
plt.title() plot title
plt.show() show the plot
In [5]:
# build a bar plot
plt.bar(['ABS', 'HIPS'],[ABS_mean, HIPS_mean])
plt.xlabel('3D-printer Fillament Material')
plt.ylabel('Tensile Strength (MPa)')
plt.title('Tensile Strength of 3-D Printed ABS and HIPS Tensile Bars')
plt.show()

Add error bars to the plot

We have a nice looking bar plot with two bars, x-axis label, y-axis label and a title. Next we will add error bars to the plot. We will add the error bars by passing a keyword argument in the plt.bar() function. The keyword argument is yerr = [list, of, error, bar, lengths]. A keyword argument is a specific type of argument passed to a function or method that must have a name associated with it. Regular function arguments just need to be in the proper order. Keyword arguments need to be pass with the form keyword_argument_name = value. The general form of the entire plt.bar() line will be:

plt.bar (['list', 'of' ,'bar', 'labels'], [list, of, bar, hights], yerr=[list, of, error, bar, lengths])

The first two arguments, ['list', 'of' ,'bar', 'labels'] and [list, of, bar, hights] just need to be in the correct order. The third argument, a keyword argument needs to include yerr =.

Our list of error bar lengths will contain the standard deviation for each set of data, ABS_stdev and HIPS_stdev.

yerr=[ABS_stdev, HIPS_stdev]
In [6]:
# build a bar plot
plt.bar(['ABS', 'HIPS'],[ABS_mean, HIPS_mean],yerr=[ABS_stdev, HIPS_stdev])
plt.xlabel('3D-printer Fillament Material')
plt.ylabel('Tensile Strength (MPa)')
plt.title('Tensile Strength of 3-D Printed ABS and HIPS Tensile Bars')
plt.show()

Add "caps" to the error bars

The error bars are on the plot, but they are just vertical lines. Typically, error bars have a horizontal lines at the top and bottom and look sort of like the capital letter I.

We can add these horizontal lines or "caps" to the top and bottom of the error bars by passing an additional keyword argument to the plt.bar() function called capsize=. We will set the capsize=10, which is a good size for this plot. You can change the capsize= number to make the horizontal lines longer or shorter.

Now our plt.bar() function call contains 4 different arguemnts:

plt.bar (['list of bar labels'], [list of bar hights], yerr = [list of error bar lengths], capsize = width)

A summary of the arugments passed to the plt.bar() function is below:

plt.bar() Arguments description
[list of bar labels] 1st argument, a list of strings which provide the labels below the bars
[list of bar heights] 2nd argument, a list of numbers which determines the height of each bar
yerr = [list of error bar lengths] a keyword argument, must include yerr =. Denotes the height of the error bars. Needs to be a list of numbers
capsize = width a keyword argument, must include capsize =. Denotes the width of the error bar horizontal "caps". Needs to be a number, not a string
In [7]:
# build the bar plot
plt.bar(['ABS', 'HIPS'],[ABS_mean, HIPS_mean],yerr=[ABS_stdev, HIPS_stdev], capsize=10)
plt.xlabel('3D-printer Fillament Material')
plt.ylabel('Tensile Strength (MPa)')
plt.title('Tensile Strength of 3-D Printed ABS and HIPS Tensile Bars')
plt.show()

Save the plot

The plot looks complete: two bars, x and y axis labels, title and error bars with caps. Now let's save the plot as an image file so we can import the plot into a Word document or PowerPoint presentation. If you are using a jupyter notebook, you can just right-click on the plot and select [copy image] or [Save Image As...]. To save a plot as an image programmatically, we use the line:

plt.savefig('filename.extension')

Matplotlib will save the plot as an image file using the file type we specify in the filename extension. For example, if we call plt.savefig('plot.png'), the plot will be saved as a .png image. If we call plt.savefig('plot.jpg') the plot will be saved as a .jpeg image.

In [8]:
# build a bar plot and save it as a .png image
plt.bar(['ABS', 'HIPS'],[ABS_mean, HIPS_mean],yerr=[ABS_stdev, HIPS_stdev], capsize=10)
plt.xlabel('3D-printer Fillament Material')
plt.ylabel('Tensile Strength (MPa)')
plt.title('Tensile Strength of 3-D Printed ABS and HIPS Tensile Bars')
plt.savefig('plot.png')
plt.show()

Increase the .png file image resolution

Depending on how the .png image file is viewed: in a jupyter notebook, on the web, in a Word document or in a PowerPoint presentation, the image may look a little blurry. This is because the .png image we created has a fairly low resolution. We can change the resolution by coding:

plt.savefig('filename.png', dpi = 300)

Where dpi=300 specifies a resolution of 300 dots per square inch. We can specify a higher resolution or lower resoltution then 300 dpi. A higher resolution will increase the image file size, but will look better when magnified.

In [9]:
# build a bar plot and save it as a .png image
plt.bar(['ABS', 'HIPS'],[ABS_mean, HIPS_mean],yerr=[ABS_stdev, HIPS_stdev], capsize=10)
plt.xlabel('3D-printer Fillament Material')
plt.ylabel('Tensile Strength (MPa)')
plt.title('Tensile Strength of 3-D Printed ABS and HIPS Tensile Bars')
plt.savefig('plot.png', dpi = 300)
plt.show()

The full script

A summary of the full script is below:

In [10]:
# import packages
from statistics import mean, stdev
import matplotlib.pyplot as plt
#include if using a jupyter notebook, remove if using a .py file
%matplotlib inline    

# data
ABS = [18.6, 21.6 ,22, 21, 18, 20.9, 21, 19.3, 18.8, 20, 19.4, 16, 23.8, 19.3, 19.7, 19.5]
HIPS = [10.4, 4.9, 10.2, 10.5, 10.9, 12.9, 11.8, 8.4, 10, 10.6, 8.6, 9.7, 10.8, 10.7, 11, 12.4, 13.3, 11.4, 14.8, 13.5]

# find the mean using the mean() function from the statistics library
ABS_mean = mean(ABS)
HIPS_mean = mean(HIPS)

# find the standard deviation using the stdev() function from the statistics library
ABS_stdev = stdev(ABS)
HIPS_stdev = stdev(HIPS)

# build a bar plot and save it as a .png image
plt.bar(['ABS', 'HIPS'],[ABS_mean, HIPS_mean],yerr=[ABS_stdev, HIPS_stdev], capsize=10)
plt.xlabel('3D-printer Fillament Material')
plt.ylabel('Tensile Strength (MPa)')
plt.title('Tensile Strength of 3-D Printed ABS and HIPS Tensile Bars')
plt.savefig('plot.png', dpi = 300)
plt.show()