matplotlib intro

You can make plots with any tool you like. But we may help you a little with the open source matplotlib library for scientific ploting, which runs with Python.


References:

Get ready

You need to install Python3.x

Check the existence of Python3 by typing python3 --version in your terminal (Powershell for Windows). Otherwise, you need to install a python environment in your device:

  1. In Windows, you could download and install python in the python official website.
  2. In Mac, you could install python with brew install python
  3. In Linux, you could install python with pip install python

You need to install matplotlib & numpy

pip install matplotlib

pip install numpy

Then you should be able import this library.
import matplotlib.pyplot as plt


You need a code editor
We recommend to use JupyterLab, a web-based interactive coding application. You could install it with pip install jupyterlab and then launch it with jupiter lab.
Modern IDEs like VsCode are also worth trying.

hello world for matplotlib

let's plot a sine function with Matplotlib:

  • Import numpy package to numerically calculate array and matplotlib to plot.
  • Construct the x and y axis value of the point.
  • Call plot() to draw a line that connects all the points
  • Save the figure and show it on screen
import numpy as np import matplotlib.pyplot as plt x = np.arange(0, 3*np.pi, 0.1) # array for x axis y = np.sin(x) # array for y axis plt.plot(x, y) # plot x vs y plt.savefig('sine.png') # save to file plt.show() # show on screen

hello world for matplotlib

import numpy as np import matplotlib.pyplot as plt x = np.arange(0, 3*np.pi, 0.1) # array for x axis y = np.sin(x) # array for y axis plt.plot(x, y) # plot x vs y plt.savefig('sine.png') # save to file plt.show() # show on screen
  • 🤔Is this figure complete?
  • Not really...

hello world for matplotlib

import numpy as np import matplotlib.pyplot as plt x = np.arange(0, 3*np.pi, 0.1) # array for x axis y = np.sin(x) # array for y axis plt.plot(x, y, label = 'sin(x)') plt.xlabel('physical quantity on x axis (unit)') plt.ylabel('physical quantity on y axis (unit)') plt.legend() # create legend plt.savefig('sine.png') # save to file plt.show() # show on screen

Elements of a figure

©️matplotlib cheatsheet

make reader-friendly figure: step 1

  • include at least x,y labels
  • figure resolution (dpi)
  • fontsize

make reader-friendly figure: step 1

No ugly blank border

plt.figure(figsize = (7,5),facecolor= 'yellow') # create a new figure plt.xlabel('physical quantity on x axis (unit)', fontsize = 12) plt.ylabel('physical quantity on y axis (unit)', fontsize = 12) plt.legend(fontsize = 12) # create legend plt.title('title for this figure',fontsize = 15) plt.savefig('sine_highQ.png', dpi = 288, bbox_inches = 'tight') # this "tight" command is important

Line plot: color

You can use 'color' argument to assign the color of the line.

plt.plot(x, y, color = 'r', label = "color = red") plt.plot(x, y+1, color = 'k', label = 'color = \'k\'')

Line plot: linestyle

You can use 'linestyle' argument to change the look of the line.

  • linestyle='-': (default) solid line
  • linestyle='--': dashed line
  • linestyle=':': dotted line
  • linestyle='': do not plot line
plt.plot(x, y, linestyle='--', label="linestyle='--'") plt.plot(x, y+1, linestyle=':', label='linestyle=\':\'') plt.plot(x, y+2, linestyle='', marker='.', label='linestyle=\'\', marker=\'.\'')

Line plot: marker

You can use 'marker' argument to label the data point on the line.

  • marker='.': dot
  • marker='+': +
  • marker='o': larger dot
  • marker='': (default) no marker
  • Try argument 'markersize', 'markeredgecolor', 'markerfacecolor', 'markeredgewidth' yourself!
plt.plot(x, y, color='b', marker='.', label='marker=\'.\'') plt.plot(x, y+1, color='b', marker='+', label='marker=\'+\'') plt.plot(x, y+2, color='b', marker='o', label='marker=\'o\'')

Line plot: linewidth and transparency

  • You can use 'linewidth' argument to adjust the width of the line.
  • You can use 'alpha' argument to adjust the transparency of the line.
plt.plot(x, y, linewidth=4, label='linewidth=4') plt.plot(x, y+1, 'k', label = 'solid black') plt.plot(x, y+1, linewidth=10, alpha = 0.5, label='linewidth=10, alpha=0.5')

Towards the complex: object-oriented class

Let's look at these lines: fig = plt.figure(figsize=(5,4),facecolor= 'white') ax = fig.add_axes([0,0,1,1]) line, = ax.plot(x,y) line.set_color('red') ax.set_xlabel('x') ax.set_ylabel('y') ax.set_title('title') fig.savefig('line_object.png')

note, there is a "," in line, = ax.plot(x,y)

why? ax.plot() returns a list of line objects.


fig, ax, line are respectively objects of figure, axes and line plots.

add_axes(), plot() and set_color() are respectively attributes / functions of these objects.


🤔why object?

review: Elements of a figure

©️matplotlib cheatsheet

Now you can change attributes of every object on this figure!

💡To modify the attribute, you usually use set_?()

subplots

sometimes we want to plot sultiple subfigures in one figure, this is often done by fig.add_subplots() or plt.subplots() . Now we create a figure with 2 times 3 panels:

fig, axes = plt.subplots(2, 3) # create subplot ((ax11, ax12, ax13), (ax21, ax22, ax23)) = axes ax11.plot(x, y) # plot on each axes ax12.plot(x, y+1) ax13.plot(x, y+2) ax21.plot(x, y+3) ax22.plot(x, y+4) ax23.plot(x, y+5)

The line fig, axes = plt.subplots(2, 3) returns a Figure and a 2x3 array of Axes objects

💡 You can also use plt.subplots() when you only want to plot one subplot!

share the same axis

Add argument sharey=True to the subplots() so that every subplot share the same y axis property (like range, scale ...)

fig, axes = plt.subplots(2, 3, sharey=True) ((ax11, ax12, ax13), (ax21, ax22, ax23)) = axes ax11.plot(x, y) ax12.plot(x, y+1) ax13.plot(x, y+2) ax21.plot(x, y+3) ax22.plot(x, y+4) ax23.plot(x, y+5)
💡 The same can be done to x-axis with sharex=True to share the same x-axis

subplots of different layout

add argument width_ratios/height_ratios=[the ratio you allocate] to the subplots() to set the width and height fraction of each subplot.

from matplotlib.gridspec import GridSpec fig = plt.figure() gs = GridSpec(2, 3, width_ratios=[1, 2, 3], height_ratios=[2, 1]) axes = [fig.add_subplot(gs[i, j]) for i in range(2) for j in range(3)] for i, ax in enumerate(axes): ax.plot(x, [v + i for v in y]) plt.show()

💡 try plt.subplots_adjust(wspace =, hspace=,) to adjust the space between subplots.

🎯 You are encouraged to investigate more complex layout with functions like G = gridspec(rows,cols,…), ax.inset_axes(extent)... You can find them on the cheatsheet.

a figure with two axis

Sometimes we want to plot 2 quantities with the same invariant in one plot, this can be done with ax.twinx().

fig, ax = plt.subplots(1,1,figsize=(5,4)) ax.plot(x, y) ax.set_ylabel('label for left y axis') ax2 = ax.twinx() ax2.plot(x, -y, color='r', label='plot on right y axis') ax2.tick_params(labelcolor='r', axis='y') # red axis label ax2.set_ylabel('label for right y axis',color='r') plt.legend()
🎯 And, ax.twiny() is also available

add colorbar in figures

We could add colorbar in a figure to represent additional information.

radius = 1 # Radius of the circular orbit num_points = 100 # Number of points to represent the orbit time = np.linspace(0, 1, num_points) # Time normalized between 0 and 1 x = radius * np.cos(2 * np.pi * time) y = radius * np.sin(2 * np.pi * time) fig, ax = plt.subplots() sc = ax.scatter(x, y, c=time, cmap='viridis', s=50) ax.plot(x, y, color='gray', linestyle='--', alpha=0.5) # Circular orbit path cbar = plt.colorbar(sc, ax=ax) cbar.set_label('Time (normalized)') ax.set_aspect('equal', adjustable='box') # Equal aspect ratio ax.set_xlabel('x (AU)') ax.set_ylabel('y (AU)') ax.set_title('Circular Orbit with Time Colorbar')
🎯 Different styles of colorbar can be applied with the cmap parameter.

make reader-friendly figure: step2

©️helong
🎯 This is an example of bad scaling!

aspect ratio

Aspect ratio determines the length ratio of unit y axis and x axis.

plt.plot(xcircle, ycircle) ax = plt.gca() ax.set_aspect('equal')
💡 Another method achieving is to adjust the figure size with plt.subplots(figsize=(6, 6)).

Logarithmic axis

sometimes the best scale is not linear

logarithmic axis

ax.set_xscale('log') ax.set_yscale('log')
💡 Here I use ax.annotate() to put descriptions on the plot.

axis range

sometimes you focus on different scales

ax.set_xlim([0, 1]) ax.set_ylim([0, 1])
💡 You can also use set_xbound([0, 1]) to achieve similar effect.

Beyond line plots

©️matplotlib cheatsheet

read data

You may need this in the homework. You can use readline() to read in .txt file.

with open('solar_system_planet.txt', 'r') as file: # Read the first line to get the headers headers = file.readline().strip().split(',') data = [] for line in file: # Read the rest of the lines for data row_data = line.strip().split(',') # Append the row data to the data list data.append(row_data) print("Headers:", headers) print("Data:", data)
  • split the string at a delimiter: string.split(',')
  • remove something at the beginning or the end: string.strip(' ')
    💡 readline() is useful to skip the lines you don't need.

    💡 Check the dataset for the proper delimiter ("|", "\t", " ")

    💡 This way we read data all as string, you need to transfer them to float.

Use Pandas for .txt/.csv/.xlsx

The library pandas read in data as python dictionary.
You can easily access different quantities by their "position" or "name".

Use Pandas for .txt/.csv/.xlsx

🎯let's try to reproduce the Mass-Radius diagram (data) of solar system objects. import pandas as pd import matplotlib.pyplot as plt data = pd.read_csv('solar_system_planet.txt',delimiter=',') radius = data['radius'] mass = data['mass'] text = data['object'] fig, ax = plt.subplots(1,1,figsize=(6,4)) ax.scatter(radius,mass,color='tab:blue',s=100,alpha= 0.5) ax.set_xlabel(r'radius ($R_\oplus$)') ax.set_ylabel(r'mass ($M_\oplus$)') for i in range(len(text)): if (text[i] == 'Venus') or (text[i] == 'Uranus'): ax.annotate(text[i], (radius[i], mass[i]), textcoords="offset points", xytext=(0,-12), ha='center') else: ax.annotate(text[i], (radius[i], mass[i]), textcoords="offset points", xytext=(0,12), ha='center') ax.set_yscale('log') ax.set_xscale('log') plt.show()

Use Pandas for .txt/.csv/.xlsx

💡 Then you should be able to get a figure like this.