An introduction to plotting with Matplotlib in Python | by Philip Wilkinson | Towards Data Science

This year, as Head of Science for the UCL Data Science Society, the society is presenting a series of 20 workshops covering topics such as introduction to Python, a Data Scientists toolkit and Machine learning methods, throughout the academic year. For each of these the aim is to create a series of small blogposts that will outline the main points with links to the full workshop for anyone who wishes to follow along. All of these can be found in our GitHub repository, and will be updated throughout the year with new workshops and challenges.
The seventh workshop in the series is an introduction to the matplotlib python package as part of the toolkit for Data Scientist series. In this workshop we introduce how to build a basic plot, plotting different information on the same graph and plotting information across multiple axes. While some of the highlights will be shared here, the full workshop including a problem sheet to test yourself can be found here.
If you have missed any of our previous workshops you can find the last three at the following links:
towardsdatascience.com
towardsdatascience.com
towardsdatascience.com
Matplotlib is another one of the core data science libraries that should be within any data scientists toolkit, along with the previously introduced libraries of Numpy and Pandas. The main purpose of this library is to create visualisations to be able to better understand the data that you have, and pandas builds on this library for its own functionality.
On the Matplotlib website is it described as:
Matplotlib is a comprehensive library for creating static, animated, and interactive visualizations in Python.
Where the aim and purpose of the library is to make plotting as easy as possible as it also states:
Matplotlib makes easy things easy and hard things possible.
While there are many other visualisation libraries out there in Python, including seaborn and plotly, this is often the first visualisation tool you learn and hence is the reason why we cover it in one of our workshops.
The first thing we need to do, before we create any plots, is to actually create data that we will use to plot! Since we have already been introduced to the Numpy library and its extensive functionality, we can use the Numpy array and its mathematical functionality to create data that we can plot. We can do this as:
# Creating an array with 100 values from 0 to 2pix = np.linspace(0,2*np.pi,100)# An array with the sine of all the values in array xy = np.sin(x)
Now we have an data for our x and y, we can start to create our plot!
For this, we can start by creating a rather basic plot where we show data quite simply as a line on an axis as follows:
# Produces the figureplt.figure()# Plots the sine functionplt.plot(x,y)
The simplicity of this is that we have only used two lines of code in order to create our graph (you could even remove the first line and it would still work!). How nice and simple is that!
Of course, this is a rather basic plot so we can start to improve it. One of the first things we notice is that we can’t necessarily see how the data line ups on the plot as there is no grid to show where the peaks and troughs of the sine wave are. We can thus add a grid to our plot using plt.grid as follows:
# Produces the figureplt.figure()# Adds a gridplt.grid(True)# Plots the sine functionplt.plot(x,y)
From this we can now see that the y value peaks at 1 and bottoms out at -1 and we could more accurately read of data in relation to where we are on the x and y value.
We can then begin to customise the look of the plot. For example, if we want to change the color from blue to red, we can specify the color as r and if we want to change the line style from a solid line to dots we can specify r. as follows:
# Produces the figureplt.figure()# Adds a gridplt.grid(True)# Plots the sine function with red dotsplt.plot(x,y,'r.')
Other ways to do this can be done using the color and linestyle paramaters of the plot to change the look as well, including a wide range of colors for the line and different looks line style as well.
Of course, we have been able to make our line look a little better and clearer, but anyone else looking at this plot may not understand what we are trying to show with the plot itself. Thus, for this we will want to add a title and labels as well to indicate what we are trying to show. We can do that as follows:
# Produces the figureplt.figure()# Adds a gridplt.grid(True)# Adds a titleplt.title("Plot of a sine function",         fontsize = 20,         pad = 15)# Adds label for the x-axisplt.xlabel("x",          fontsize = 15,          labelpad = 20)# Adds label for the y-axisplt.ylabel("sin(x)",          fontsize = 15,          labelpad = 15)# Plots the sine function with red + signsplt.plot(x,y,'r+')
Where we have used the plt.xlabel , plt.ylabel and plt.title functions to add these to the plot. We have also specified fontsize to dictate the size of the font used on the labels and labelpad and pad to move the labels away from the axis so that they become clearer to read.
From this, we can start to add to build up more functionality into our plots and create our own style that we can use across all of the plots we create. However, Matplotlib has a wealth of inbuilt style sheets that we can access using plt.style.use(`namedstyle`) . One of my favourite ones from this is the fivethirtyeight style sheet because of its ability to produce nice and clear visuals, along with a clean and easily recognisable colour palette. We can implement this as:
# Changing style to fivethityeightplt.style.use('fivethirtyeight')# Produces the figureplt.figure()# Adds a gridplt.grid(True)# Adds a titleplt.title("Plot of a sine function",         fontsize = 20,         pad = 15)# Adds label for the x-axisplt.xlabel("x",          fontsize = 15,          labelpad = 20)# Adds label for the y-axisplt.ylabel("sin(x)",          fontsize = 15,          labelpad = 15)# Plots the sine function with red + signsplt.plot(x,y, "+")
Which now looks a lot cleaner! More of these, along with examples of what they look like, can be found at this link here.
While we now have a nice looking plot that shows all the information we would want from this, what if we wanted to add more information to the same plot? We can simply do this by reusing the same axis and plotting the new data.
In our case, since we have already created a sine wave, we can also create a cosine wave using the same x series to compare how they change over the same values. We can do this as follows:
# Generates an array of cos(x) valuesy1 = np.cos(x)# Produces the figureplt.figure()# Adds a gridplt.grid(True)# Adds a titleplt.title("Plot of a sine and cosine function")# Adds label for the x-axisplt.xlabel("x")# Adds label for the y-axisplt.ylabel("y")# Plots the sine function with red + signsplt.plot(x,y,'r+')# Plots the cos function with green crossesplt.plot(x,y1,'gx')
Great! We can see we have been able to use the same functions we have done previously to add the grid and the labels, but now we have been able to add the cosine function as well with green crosses. The only issue now is that unless we saw the original plot with the sine function on (or we know what a sine function should look like), we don’t necessarily know how we can tell them apart. This is where a legend comes in handy!
In order to add a legend to our plots we need to specify a label for the plots for both the sine and cosine function to be able to differentiate them. This is done by adding an additional argument label= to the plt.plot function. This label needs to be set to the string which we want to label the plot. Then we add an additional line of plt.legend for the legend to appear. The optional argument here loc="best" is often used which simply tries to ensure that the legend is placed in the most suitable location of the plot. We can try this as follows:
# Produces the figureplt.figure()# Adds a gridplt.grid(True)# Adds a titleplt.title("Plot of a sine and cosine function")# Adds label for the x-axisplt.xlabel("x")# Adds label for the y-axisplt.ylabel("y")# Plots the sine function with red + signs and defines a legend labelplt.plot(x,y,'r+',label="sin(x)")# Plots the cos function with green crosses and defines a legend labelplt.plot(x,y1,'gx',label="cos(x)")# Adds a legend in the best positionplt.legend(loc='best')
Now we can clearly tell which is the sine function and which is the cosine function. The only issue that remains is that we now have some white space at either end of the plot where our lines run out essentially. We can thus try to limit our axis so that we only show where values are actually plotted using the plt.xlim and plt.ylim functions as follows:
# Produces the figureplt.figure()# Adds a gridplt.grid(True)# Adds a titleplt.title("Plot of a sine and cosine function")# Adds label for the x-axisplt.xlabel("x")# Adds label for the y-axisplt.ylabel("y")# Defines a region along the x-axis to be displayedplt.xlim(0,2*np.pi)# Plots the sine function with red + signs and defines a legend labelplt.plot(x,y,'r+',label="sin(x)")# Plots the cos function with green crosses and defines a legend labelplt.plot(x,y1,'gx',label="cos(x)")# Adds a legend in the best positionplt.legend(loc='best')
So far we have been able to create an plot showing a single piece of data, then we have been able to create a plot showing multiple pieces of data. What if we had two seperate pieces of data that we wanted to show on multiple plots but we didn’t want to create two seperate plots? Well, we can do this by create an array of subplots!
There are two ways we can do this. The first is create a base figure, as we have done already, and then add subplots to the original figure to which we can then add our data. For this, we can use fig.add_subplot(1,2,1) where the first two numbers indicate the size of the array created (here 1 row and 2 columns), while the third number indicates which subplot this will be. We can assign this back to a variable to create it as an axis. The only difference here between what we previously did and here is now we have an axis where instead of using fig.title or fig.xlabel we now have to use ax.set_title and ax.set_xlabel . For example, we can create two sub axes to add our plots to as we did before:
# Defines a variable for your array of subplotsfig = plt.figure(figsize=(10,5))# Adds a subplot to the arrayax1 = fig.add_subplot(1,2,1)# Plots the sine function on the first subplotax1.plot(x,y1,'r')ax1.set_title("Sine function")ax1.set_xlabel("x")ax1.set_ylabel("y")ax1.grid(True)# Plots the cosine function on the second subplotax2 = fig.add_subplot(1,2,2)ax2.plot(x,y2,'g')ax2.set_title("Cosine function")ax2.set_xlabel("x")ax2.set_ylabel("y")ax2.grid(True)#to ensure no overlappingplt.tight_layout()
We can see now we have created two seperate axis to which we can then plot our data!
The alternative is to use fig, ax = plt.subplots(1,2, figsize = (10,5)) to specify straight away that we are creating subplots where fig is our base axis and ax is an array of axis which we can access just as we would a list or an array. We can thus plot the same information as have done previously as follows:
fig, ax = plt.subplots(1,2, figsize = (10,5))# Plots the sine function on the first subplotax[0].plot(x,y1,'r')ax[0].set_title("Sine function")ax[0].set_xlabel("x")ax[0].set_ylabel("y")ax[0].grid(True)# Plots the cosine function on the second subplotax[1].plot(x,y2,'g')ax[1].set_title("Cosine function")ax[1].set_xlabel("x")ax[1].set_ylabel("y")ax[1].grid(True)#to ensure no overlappingplt.tight_layout()
Where we now have the exact same plot but using slightly different notation! We can then use these to create multiple arrays of subplots to show multiple types of data within the same overall plot!
To this end, the latter method of creating subplots is more often used because you are specifying straight away that you are creating several sub-axis, rather than specifying this later on. It is also often used when you are creating a single axis (specifying 1,1 ) because it ensures that everything is plotted on the same axis when you are plotting more than one piece of information!
Of course, Matplotlib can do a lot more than just plot basic information like this, and we cover creating matrix plots, choropleth plots, radar plots and more in the actual workshop itself. Matplotlib is a very extensive library and it allows you to do a lot with it, including box plots, scatter plots, bar charts and histograms among others, but there are also other visualisation libraries out there such as seaborn and plotly. I would recommend you explore and practice plotting, including trying our problem worksheet to challenge you!
The full workshop notebook, along with further examples and challenges, can be found HERE. If you want any further information on our society feel free to follow us on our socials:
Facebook: https://www.facebook.com/ucldata
Instagram: https://www.instagram.com/ucl.datasci/
LinkedIn: https://www.linkedin.com/company/ucldata/
And if you want to keep up date with stories from the UCL Data Science Society and other amazing authors, feel free to sign up to medium using my referral code below.