2. Visualization#

Visualizatin is vital in data analysis and scientific computing, to

  • get intuitive understanding

  • come up with a new hypothesis

  • detect a bug or data anormaly

That is why we’ll cover this topic at the beginning of this course.

Matplotlib#

Matplotlib is the standard graphics package for Python. It mimics many graphics functions of MATLAB.
The Matplotlib gallery (http://matplotlib.org/stable/gallery) illustrates variety of plots.

import numpy as np
import matplotlib.pyplot as plt

Usually matplotlib opens a window for a new plot.

A nice feature of Jupyter notebook is that you can embed the figures produced by your program within the notebook by the following magic command
%matplotlib inline
(It may be a default setting in recent jupyter notebook).

%matplotlib inline

Plotting functions#

The standard way is to prepare an array for x values, compute y values, and call plot( ) function.

# make an array from 0 to 10, the default is 50 points
x = np.linspace(0, 10)
# comupute a function for each point
y = x*np.sin(x)
# plot the points
plt.plot(y)  # x is the index of y
[<matplotlib.lines.Line2D at 0x11d73b210>]
_images/109e7e1b99653ae9414606d2a6600ef0738983abe2ae92334957b8c4f092532c.png

There are multiple ways to pass variables to plot():

  • plot(y): x is assumed as the indices of y

  • plot(x, y): specify both x and y values

  • plot(x1, y1, x2, y2,...): multiple lines

  • plot(x, Y): lines for columns of matrix Y

# specify both x and y values
plt.plot(x, y)
[<matplotlib.lines.Line2D at 0x11d84d3d0>]
_images/f6d86194c1d610602732251e77ae7c5f042ceaf4c8eb4d0c8de566b3df422d26.png
# take another function of x
y2 = x*np.cos(x)
# plot two lines
plt.plot(x, y, x, y2)
[<matplotlib.lines.Line2D at 0x11dcac390>,
 <matplotlib.lines.Line2D at 0x11dc94dd0>]
_images/4e46b6512f11a6c60639b7aeba3d05dd623cbc8ba1401cab900be6eb2fa4a9d3.png
# phase plot
plt.plot(y, y2);
# you can supress <matplotlib...> output by ;
_images/6d7375ec46774708db7bb26f4032a2fab44e22220d80ec5cc0391e726f1ae4c8.png
# plot multiple lines by a matrix
Y = np.array([y, y2])  # stack data in two rows
plt.plot(x, Y.T); # transpose to give data in two columns
_images/4e46b6512f11a6c60639b7aeba3d05dd623cbc8ba1401cab900be6eb2fa4a9d3.png
# plot multiple lines by a matrix
Y = np.array([np.sin(k*x) for k in range(4)])
plt.plot(x, Y.T);
_images/59ac8c22fd8e4c38b8aa9fbdf8f4707105810796d4c26891f19f866163b2a51a.png

Options for plotting#

Line styles can be specified by

  • color= (or c= ) for color by code, name, RGB or RGBA

    • code: ‘r’, ‘g’, ‘b’, ‘y’, ‘c’, ‘m’, ‘k’, ‘w’

  • marker= for marker style

    • code: ‘.’, ‘o’, ‘+’, ‘*’, ‘^’, …

  • linestyle= (or ls= ) for line style

    • code: ‘-’, ‘–’, ‘:’, ‘-.’, …

  • linewidth= (or lw= ) for line width

  • a string of color, marker and line sytel codes, e.g. ‘ro:’

# using code string
plt.plot(x, y, 'm:', x, y2, 'c*');  # magenta dash-dot, cyan circle
_images/5f60418cde7dc9c9d7186625f47af524e5bc5508db8bd10408dc6286e80fc89e.png
# using keyword=value
plt.plot(x, y, c=[0.2,0.5,0.8,0.5], marker='o', markersize=10, ls='-.', lw=2);
_images/25195c0cfafdd3ff9454ff3de6cb2573663be930e4c9fe415db1381466007a4a.png

It’s a good practice to add axis lables and plot title.
You can use Latex format by \( \).

plt.plot(x, y)
plt.title('oscillation')
plt.xlabel('time ($\\mu s$)')  # $ $ for latex code with \\ for symbols
plt.ylabel('amplitude')
Text(0, 0.5, 'amplitude')
_images/58aed7ea3233711d85354b9100ece809b776f8a268f1299be69f5e765ae3b7ad.png

It is also nice to add a legend box.

ax = plt.plot(x, y, x, y2)
plt.legend(('x sin x','x cos x'))  # second line in LaTex
<matplotlib.legend.Legend at 0x11dfc7f50>
_images/1e3625e3e23111c2a4343b008c56c7974fe7ff6decb7aaaa7aa605dc728c84d5.png

The texts in a figure tend to be too small when included in a slide or a paper.
You can control the default font size by rcParams.update() and specifying fontsize for particular labels.

# set default font size to 20 point
plt.rcParams.update({'font.size': 20})
ax = plt.plot(x, y, x, y2)
plt.title('oscillation', fontsize=28)  # title in 28 point
plt.xlabel('time ($\\mu s$)')
plt.ylabel('amplitude')
plt.legend(('t sin t','t cos t'))
<matplotlib.legend.Legend at 0x11dea6950>
_images/9565a7855687f21b25990fb23f5bff2e6c97e00e5e5adc3a1a9382124de159ed.png

You can control axis ranges and scaling.

plt.plot(x, y)
plt.xlim(-1, 5)
plt.ylim(-4, 4)
(-4.0, 4.0)
_images/301a113a94c3652daf79f82727196f3c481d3c9b045983e501e4f6633966e8b3.png
plt.plot(y, y2)
plt.axis('equal')  # equal scaling for x and y
(-6.10798067784125, 8.582949839004911, -10.247801600732576, 7.121229063313089)
_images/6393e2ea436ac24f07fd728190c163ec8076e962dcd2e18813ce68579895729d.png
plt.plot(y, y2)
plt.axis('square')  # in square plot area
(-6.10798067784125, 11.261049986204412, -10.247801600732576, 7.121229063313088)
_images/2c3d0baeb58f98901617debed97e69e9400c2c954a261850db6e6ba6c45e840f.png

You can create a fiure of your preferred size by plt.figure() function

fig = plt.figure(figsize=(6, 6))
plt.plot(y, y2)
[<matplotlib.lines.Line2D at 0x11e95d450>]
_images/958681d750df76b5940f5fffc8d517481c653f512325cb5fd3a8248a92684bda.png

Bar plot and histogram#

i = np.arange(10)
j = i**2
plt.bar(i, j)
<BarContainer object of 10 artists>
_images/816c13cd383e3d321a338f28d9d33301f140920a3b7b2bd28a2022b2d2f6da96.png

np.random.randn() gives random numbers from the normal distribution

z = np.random.randn(500)
plt.hist(z)
(array([  2.,   2.,  26.,  61., 117., 117., 118.,  44.,  11.,   2.]),
 array([-3.72532545, -3.00287778, -2.28043011, -1.55798244, -0.83553476,
        -0.11308709,  0.60936058,  1.33180825,  2.05425592,  2.7767036 ,
         3.49915127]),
 <BarContainer object of 10 artists>)
_images/f04943ead3b5e42e059c43932771a50506cfb9aecaf57bd43919a7fd3ffab663.png
plt.hist(z, bins=20)
(array([ 1.,  1.,  0.,  2., 11., 15., 18., 43., 56., 61., 57., 60., 63.,
        55., 28., 16.,  8.,  3.,  1.,  1.]),
 array([-3.72532545, -3.36410162, -3.00287778, -2.64165394, -2.28043011,
        -1.91920627, -1.55798244, -1.1967586 , -0.83553476, -0.47431093,
        -0.11308709,  0.24813674,  0.60936058,  0.97058442,  1.33180825,
         1.69303209,  2.05425592,  2.41547976,  2.7767036 ,  3.13792743,
         3.49915127]),
 <BarContainer object of 20 artists>)
_images/76a7e58978cefdf243ded3fe1726c7ee64d00b7acd23a40233730e6057cbe4e4.png

Subplot and axes#

You can create multiple axes in a figure by subplot(rows, columns, index).
It uses a MATLAB legacy for index starting from 1.

plt.tight_layout() adjusts the space between axes.

plt.subplot(2, 2, 1)
plt.plot(x, y)
plt.xlabel('x'); plt.ylabel('y')
plt.subplot(2, 2, 2)
plt.plot(y, x)
plt.xlabel('y'); plt.ylabel('x')
plt.subplot(2, 2, 3)
plt.plot(x, y2)
plt.xlabel('x'); plt.ylabel('y2')
plt.subplot(2, 2, 4)
plt.plot(y, y2)
plt.xlabel('y'); plt.ylabel('y2')
plt.tight_layout()
_images/a58eb9d988df934068e33d67a911440e930f4db6b644384e14a37d82c221f774.png

Figure and axes#

When you make a plot, matplotlib creates a figure object with an axes object.
You can use gcf() and gca() to identify them and getp() and setp() to access their parameters.

plt.plot(x, y)
fig = plt.gcf()  # get current figure
plt.getp(fig)  # show all parameters
    agg_filter = None
    alpha = None
    animated = False
    axes = [<Axes: >]
    children = [<matplotlib.patches.Rectangle object at 0x11eae13...
    clip_box = None
    clip_on = True
    clip_path = None
    constrained_layout = False
    constrained_layout_pads = (None, None, None, None)
    default_bbox_extra_artists = [<Axes: >, <matplotlib.spines.Spine object at 0x11...
    dpi = 100.0
    edgecolor = (1.0, 1.0, 1.0, 1.0)
    facecolor = (1.0, 1.0, 1.0, 1.0)
    figheight = 4.8
    figure = Figure(640x480)
    figwidth = 6.4
    frameon = True
    gid = None
    in_layout = True
    label = 
    layout_engine = None
    linewidth = 0.0
    mouseover = False
    path_effects = []
    picker = None
    rasterized = False
    size_inches = [6.4 4.8]
    sketch_params = None
    snap = None
    suptitle = 
    supxlabel = 
    supylabel = 
    tight_layout = False
    tightbbox = TransformedBbox(     Bbox(x0=2.9027777777777715, y...
    transform = IdentityTransform()
    transformed_clip_path_and_affine = (None, None)
    url = None
    visible = True
    window_extent = TransformedBbox(     Bbox(x0=0.0, y0=0.0, x1=6.4, ...
    zorder = 0
_images/8d154528161b3c0b957f99b7d787247a09c11e737dd461cf1439f466e5076091.png
plt.plot(x, y)
fig = plt.gcf()
plt.setp(fig, size_inches=(8,4), facecolor=[0.5,0.5,0.5])
[None, None]
_images/3188cf0566e9bf76fa0c0edefea40fdc26c92b4449464aee7e7abb7f886d08f5.png
plt.plot(x, y)
ax = plt.gca()  # get current axes
plt.getp(ax)
plt.setp(ax, facecolor='y')  # change parameters
    adjustable = box
    agg_filter = None
    alpha = None
    anchor = C
    animated = False
    aspect = auto
    autoscale_on = True
    autoscalex_on = True
    autoscaley_on = True
    axes_locator = None
    axisbelow = line
    box_aspect = None
    children = [<matplotlib.lines.Line2D object at 0x11ec8e250>, ...
    clip_box = None
    clip_on = True
    clip_path = None
    data_ratio = 1.3355391378951056
    default_bbox_extra_artists = [<matplotlib.spines.Spine object at 0x11ec800d0>, ...
    facecolor or fc = (1.0, 1.0, 1.0, 1.0)
    figure = Figure(640x480)
    frame_on = True
    gid = None
    gridspec = GridSpec(1, 1)
    images = <a list of 0 AxesImage objects>
    in_layout = True
    label = 
    legend = None
    legend_handles_labels = ([], [])
    lines = <a list of 1 Line2D objects>
    mouseover = False
    navigate = True
    navigate_mode = None
    path_effects = []
    picker = None
    position = Bbox(x0=0.125, y0=0.10999999999999999, x1=0.9, y1=...
    rasterization_zorder = None
    rasterized = False
    shared_x_axes = <matplotlib.cbook.GrouperView object at 0x11ec29bd...
    shared_y_axes = <matplotlib.cbook.GrouperView object at 0x11ecb06d...
    sketch_params = None
    snap = None
    subplotspec = GridSpec(1, 1)[0:1, 0:1]
    tightbbox = Bbox(x0=2.9027777777777715, y0=15.077777777777776,...
    title = 
    transform = IdentityTransform()
    transformed_clip_path_and_affine = (None, None)
    url = None
    visible = True
    window_extent = TransformedBbox(     Bbox(x0=0.125, y0=0.109999999...
    xaxis = XAxis(80.0,52.8)
    xaxis_transform = BlendedGenericTransform(     CompositeGenericTrans...
    xbound = (-0.5, 10.5)
    xgridlines = <a list of 7 Line2D gridline objects>
    xlabel = 
    xlim = (-0.5, 10.5)
    xmajorticklabels = [Text(-2.5, 0, '−2.5'), Text(0.0, 0, '0.0'), Text(...
    xminorticklabels = []
    xscale = linear
    xticklabels = [Text(-2.5, 0, '−2.5'), Text(0.0, 0, '0.0'), Text(...
    xticklines = <a list of 14 Line2D ticklines objects>
    xticks = [-2.5  0.   2.5  5.   7.5 10. ]...
    yaxis = YAxis(80.0,52.8)
    yaxis_transform = BlendedGenericTransform(     BboxTransformTo(     ...
    ybound = (-6.10798067784125, 8.582949839004911)
    ygridlines = <a list of 8 Line2D gridline objects>
    ylabel = 
    ylim = (-6.10798067784125, 8.582949839004911)
    ymajorticklabels = [Text(0, -7.5, '−7.5'), Text(0, -5.0, '−5.0'), Tex...
    yminorticklabels = []
    yscale = linear
    yticklabels = [Text(0, -7.5, '−7.5'), Text(0, -5.0, '−5.0'), Tex...
    yticklines = <a list of 16 Line2D ticklines objects>
    yticks = [-7.5 -5.  -2.5  0.   2.5  5. ]...
    zorder = 0
[None]
_images/04b04b3d3ede0c2ddfa1782ff1511fba1e4f54d9450847cc7cb5343d8a47c982.png

Visualizing data in 2D#

A standard way for visualizing pariwise data is a scatter plot.

n = 100
x = np.random.uniform(-1, 1, n)  # n points in [-1,1]
y = 2*x + np.random.randn(n)  # scale and add noise
plt.plot(x, y, 'o')
[<matplotlib.lines.Line2D at 0x11ece7710>]
_images/3b3812b5c80c1f6b7666855b92a25477a5489d4c741bee7d7ea091985a67ad1b.png

By scatterplot( ) you can specify the size and the color of each point to visualize higher dimension information.

z = x**2 + y**2
c = y - 2*x
# z for size, c for color
plt.scatter(x, y, z, c)
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x11ed023d0>
_images/ecc3a872c28719c9ad32b1ca35165a2cdfac235c362c392c4b653d49385715d4.png

Visualizing a matrix or a function in 2D space#

meshgrid() is for preparing x and y values in a grid.

x = np.linspace(-4, 4, 9)
y = np.linspace(-3, 3, 7)
print(x, y)
X, Y = np.meshgrid(x, y)
print(X, Y)
[-4. -3. -2. -1.  0.  1.  2.  3.  4.] [-3. -2. -1.  0.  1.  2.  3.]
[[-4. -3. -2. -1.  0.  1.  2.  3.  4.]
 [-4. -3. -2. -1.  0.  1.  2.  3.  4.]
 [-4. -3. -2. -1.  0.  1.  2.  3.  4.]
 [-4. -3. -2. -1.  0.  1.  2.  3.  4.]
 [-4. -3. -2. -1.  0.  1.  2.  3.  4.]
 [-4. -3. -2. -1.  0.  1.  2.  3.  4.]
 [-4. -3. -2. -1.  0.  1.  2.  3.  4.]] [[-3. -3. -3. -3. -3. -3. -3. -3. -3.]
 [-2. -2. -2. -2. -2. -2. -2. -2. -2.]
 [-1. -1. -1. -1. -1. -1. -1. -1. -1.]
 [ 0.  0.  0.  0.  0.  0.  0.  0.  0.]
 [ 1.  1.  1.  1.  1.  1.  1.  1.  1.]
 [ 2.  2.  2.  2.  2.  2.  2.  2.  2.]
 [ 3.  3.  3.  3.  3.  3.  3.  3.  3.]]

We can use imshow() to visualize a matrix as an image.

Z = X**2 * Y
print(Z)
plt.imshow(Z)
[[-48. -27. -12.  -3.  -0.  -3. -12. -27. -48.]
 [-32. -18.  -8.  -2.  -0.  -2.  -8. -18. -32.]
 [-16.  -9.  -4.  -1.  -0.  -1.  -4.  -9. -16.]
 [  0.   0.   0.   0.   0.   0.   0.   0.   0.]
 [ 16.   9.   4.   1.   0.   1.   4.   9.  16.]
 [ 32.  18.   8.   2.   0.   2.   8.  18.  32.]
 [ 48.  27.  12.   3.   0.   3.  12.  27.  48.]]
<matplotlib.image.AxesImage at 0x11ee2c4d0>
_images/6ce619bfce973c399799cc1144f753979e5615f212f90e1152e93aea41859553.png
# some more options
plt.imshow(Z, origin='lower', extent=(-4.5, 4.5, -3.5, 3.5))
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x11eea1d90>
_images/00804c93abf1fd094d5ad4be4b7a8ba2880682213ef9e3520abc74b222db4247.png

color maps#

imshow( ) maps a scalar Z value to color by a colormap. The standard color map viridis is friedly to color blindness and monochrome printing. You can also choose other color maps.

plt.imshow(Z, cmap='jet')
<matplotlib.image.AxesImage at 0x11ef2f090>
_images/b42107ed54db8ebaab8d90d5219004ceadcb0fd8545c0ed3c68878afe4bb428d.png

contour plot#

x = np.linspace(-4, 4, 25)
y = np.linspace(-4, 4, 25)
X, Y = np.meshgrid(x, y)
Z = X**2 + 2*Y**2
plt.contour(X, Y, Z)
plt.axis('square')
(-4.0, 4.0, -4.0, 4.0)
_images/3bed4746071c469ea82c998be675ffcdb73cbba798106df4c7db42e16644e761.png

vector field by quiver( )#

x = np.linspace(-3, 3, 15)
y = np.linspace(-3, 3, 15)
X, Y = np.meshgrid(x, y)
# Van del Pol model
k = 1  # paramter
U = Y  # dx/dt
V = k*(1 - X**2)*Y - X  # dy/dt
plt.quiver(X, Y, U, V)
<matplotlib.quiver.Quiver at 0x11edd1390>
_images/0506ad1fedc467a7d4584dbb66ae00da58aeef40bbd0ff10daf12a5bd34fefee.png

Saving the image#

You can save a plot as a .png file by right-clicking it and choosing a pop-up menu like “save image as …” by the browser.

You can use plt.savefig() function to save it in other formats.

plt.quiver(X, Y, U, V)
plt.title('Van der Pol model')
plt.xlabel('u')
plt.ylabel('v')
plt.axis('square')
plt.savefig('VdP.pdf')
_images/99feb11c07f06b94413f3c5d86f0999fda1235fd4df3fbf424c7533454963bf2.png
!open VdP.pdf