The Data Viz Wiz: Introducing Matplotlib
Tags: python, matplotlib, datavisualization, datascience
Published: 2020-04-30 18:20:56

---
title: The Data Viz Wiz: Introducing Matplotlib
published: true
description: 
tags: #python #matplotlib #datavisualization #datascience
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/atrdlrecjcr54j0fja0c.jpg
---

A picture is worth a thousand words :grinning:! You can *derive valuable insights* from data and also *communicate these insights* via data visualization.

We would clearly see trends and derive insights via Python’s **Matplotlib** library, which is the foundational library used by many visualization tools. There are 3 main layers in Matplotlib’s architecture and from top to bottom in terms of the high-level commands, they are - 
 - **matplotlib.pyplot** module  - the *scripting layer* which is often called **procedural plotting** and is used when you want to quickly create plots and get done with it. This layer is designed to work like a MATLAB script.
 - **matplotlib.artist** module  - the *artist layer* which is often called **objected-oriented plotting** and you can do a lot more customizations because you have much more control. **_Note that this layer also uses the pyplot module for a few functions like creating the figure - we would see in the examples below that even in the object-oriented approach, pyplot is still used in creating the figure, which holds anything plotted, as you would see below_**.
 - **matplotlib.backend_bases** module  - the *backend layer* - Matplotlib can be used in many ways and also have different outputs formats e.g Matplotlib can be run from the python shell and we have plotting windows pop up; or it is run via Jupyter notebooks and plots are drawn inline. So, the backend layer exists to support these several use cases and outputs.

So, with what we have above, there are essentially 2 ways to create plots in Matplotlib - 
 - The procedural way - this is where we mostly do *plt.xxx*
 - The object-oriented way - this is where we mostly do *ax.xxx*

Everything we plot in Matplotlib is contained in a *figure object* which can contain one or more *axes*. Take a  look at *figure anatomy image* below -
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/86qv27z6t7ys5ok9br9q.jpg)

We would focus on the object-oriented way in this piece since we can do a lot more customizations with it. Also, note that there are different ways to create an axes - *an axes is contained in a figure* as seen above. These different ways of creating an axes still produce the same results - I will highlight the different ways. Now, let’s kick off some Matplotlib plotting by taking a look at *1.py* below:

{% gist https://gist.github.com/joyadauche/a044c680338e0752fa12b71c6aedc480 file=1.py %}

*1.py* produces a *figure with 1 axes* image below -
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/0uki7m4zgfp5jcgw47t0.png)

In *1.py* above - 
 - Line 1 = pyplot is a module in Matplotlib which will help us in plotting. It is conventionally imported with the alias *plt*
 - Line 3 = when *plt.subplots()* is called without any arguments, it creates 2 objects - a **Figure** object and an **Axes** object. 
The *Figure* object is like a container that holds the axes and a *figure can contain multiple axes*.
The *Axes* object is where we plot our data to visualize it
 - Line 4 = displays the plot - which is a *figure with empty axes* because no data has been added yet

There are different ways used in creating an axes in Matplotlib - *plt.subplot()*, *plt.subplots()* and *plt.axes()* are all from the *scripting layer* and it corresponds to *fig.add_subplot()*, *fig.subplots()* and *fig.add_axes()* from the *artist layer*. *Lines 6-44* shows other ways of creating an axes which produce the same result.
- Line 16 - **fig.subplot(1, 1, 1)** means 1 row, 1 column and the last argument gives the position of the subplot which is the 1st subplot in this case - *the last argument has to be less than or equal to the product of the 1st and 2nd arguments*
- Line 28 - **fig.subplots(1, 1)** means 1 row and 1 column
- Lines 39 and 43, the common arguments **[0.1, 0.1, 0.8, 0.8]** makes the axes 10% from the left of the figure, 10% from the bottom of the figure, 80% width of the figure, and 80% height of the figure.

Now let’s add some **fictional data** to our figure! See *2.py* below - 
{% gist https://gist.github.com/joyadauche/a044c680338e0752fa12b71c6aedc480 file=2.py %}

*2.py* produces a **_line plot of Lagos average monthly temperature_** below -
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/h13gxwwd3blpsol16d2m.png)

In the line plot above, we can clearly see the temperature pattern as it increases from *Jan* to *Jul* then it starts decreasing from *Aug* to *Nov* then it starts increasing again. Imagine you have lots of data, would you rather go through the pain of reading off average temperatures from a table or use the line plot which shows clearer trends in the data?

We can even add more **fictional data** like in *3.py* below -
{% gist https://gist.github.com/joyadauche/a044c680338e0752fa12b71c6aedc480 file=3.py %}

*3.py* above produces a **_line plot of Lagos and Abuja average monthly temperature_** we see below - 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/xesynhe1rkpndioqh3ue.png)


In the image above, we can clearly see -  
- **Abuja is warmer than Lagos for the first 8 months** - perhaps you might prefer chilling in Lagos for the first 8 months of the year :wink:?
- **Abuja has a drop in temperature in September which is even lower than that of Lagos for the same month** - seems you might want to travel back to Abuja this time perhaps to meet with family :wink:?
- **But hey chill! looks like for the rest of the year, there is a rise in temperature which is higher than that of Lagos** - Ermmm! I think you might want to just chill in Lagos for a bit and monitor the trends for a while :wink:?

The line plots we have seen so far shows us the monthly trends for the average temperature across different cities but **it does not communicate the data properly in a way that it can be easily understood**. This is where we have to **_customize_** our plot in order to communicate the information more clearly. Let’s see *4.py* below for some customizations -
{% gist https://gist.github.com/joyadauche/a044c680338e0752fa12b71c6aedc480 file=4.py %}

*4.py* above produces a **_customized line plot of Lagos average monthly temperature values_** below - 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/boiiuqenco7mfvsg1glt.png)

In *4.py* above - 
- In lines 12-14, we added these arguments:
   - **marker** which shows the actual data points
   - **markersize**, **makerfacecolor**, **markeredgewidth**, **markeredgecolor** which customizes the marker by *increasing its size*, *adding colour to its fill* and giving the marker outline *width* and *colour* respectively
   - **linestyle**, **linewidth** and **color** which gives the line in the plot its style, width and color. *linestyle* can be shortened to be *ls* while *linewidth* can be shortened to be *lw*
- Line 16 - sets the label for the x-axis
- Line 17 - sets the label for the y-axis
- Line 18 - sets the title for the line plot and this provides *context for our visualization*
- Note that every *customization* is done before a call to *plt.show()* is made.

To customize the **_line plot of Lagos and Abuja average monthly temperature_**, see *5.py* below - 
{% gist https://gist.github.com/joyadauche/a044c680338e0752fa12b71c6aedc480 file=5.py %}

*5.py* above produces a _**customized line plot of Lagos and Abuja average monthly temperature values**_ below -
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/1i9a1iqdq7zxamomljd2.png)


Sometimes, when we add more data to a plot like in *customized line plot of Lagos and Abuja average monthly temperature values* above, it makes it look so busy and it becomes a big mess which conceals patterns or trends in data rather than conveying them. The solution to this is to use **subplots**. Subplots are several small plots which show identical data under different conditions e.g temperature values data for different cities. Let’s see *6.py* below for an example -
{% gist https://gist.github.com/joyadauche/a044c680338e0752fa12b71c6aedc480 file=6.py %}

*6.py* above produces **_subplots of the average monthly temperature across cities_**
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/95974z0nl3nur9srq0lc.png)

In *6.py* above - 
- Line 16 - *sharey = True* ensures subplots have the same range on the y-axis based on the data from both datasets
- Line 22 - since the subplots are on top of each other, we can just add the x-axis label to the bottom plot

In the example given in *6.py* above, we got a 1-dimensional axes object since one of the dimensions is 1. For a 2-dimensional array, we can access the object in several ways like we see in *lines 29-69* - 
- 1a, 1b and 1c show different ways we can access the axes object: via **regular indexing we do in Python**, via **flattening the 2D array** and via **tuple unpacking** respectively.
- The rest shows the different usage patterns when *ax* is an array of axes objects.

As seen above you can create axes via different ways e.g. by adding an axes to the figure via *fig.add_axes()*, this would not be a subplot, but an axes which is an object of *matplotlib.axes._axes.Axes*. An axes, which is created via the subplot way is a *matplotlib.axes._subplots.AxesSubplot*. This class *derives* from *matplotlib.axes._axes.Axes*, thus this *subplot is an axes*. Hence, **every subplot is an axes object but not every Axes object is a AxesSubplot object**. An axes contain the x-axis and the y-axis. Be it singular or plural, it is still called *axes*. 


Alrightee!!! Glad we are gradually demystifying the mystical Matplotlib library. I know you will eventually get the hang of it and begin your tour in becoming a Data Viz Wiz! Stay tuned to this series for my next article on **Visualizing categorical and quantitative variables via Matplotlib**! Have an amazing and fulfilled week ahead!