3.15. Advanced Matplotlib

3.15.1. Customizing Ticks

Matplotlib’s default tick locators and formatters are designed to be generally sufficient in many situations, but are not suitable for every plot.

%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
import numpy as np

3.15.1.1. Hiding Ticks or Lables

ax = plt.axes()
ax.plot(np.random.rand(100))
ax.yaxis.set_major_locator(plt.NullLocator())
ax.xaxis.set_major_formatter(plt.NullFormatter())
fig, ax = plt.subplots(4, 4, figsize=(4, 4))
fig.subplots_adjust(hspace=0, wspace=0)
from sklearn.datasets import fetch_olivetti_faces
faces = fetch_olivetti_faces().images
for i in range(4):
    for j in range(4):
        ax[i, j].xaxis.set_major_locator(plt.NullLocator())
        ax[i, j].yaxis.set_major_locator(plt.NullLocator())
        ax[i, j].imshow(faces[10 * i + j], cmap="bone")

3.15.1.2. Reducing or Increasing the Number of Ticks

fig, ax = plt.subplots(4, 4, sharex=True, sharey=True)
for axi in ax.flat:
    axi.xaxis.set_major_locator(plt.MaxNLocator(5))
    axi.yaxis.set_major_locator(plt.MaxNLocator(5))
fig

3.15.1.3. Fancy Tick Formats

# Plot a sine and cosine curve
fig, ax = plt.subplots()
x = np.linspace(0, 3 * np.pi, 2000)
ax.plot(x, np.sin(x), lw=3, label='Sine')
ax.plot(x, np.cos(x), lw=3, label='Cosine')
# Set up grid, legend, and limits
ax.grid(True)
ax.legend(frameon=False)
ax.axis('equal')
ax.set_xlim(0, 3 * np.pi)
ax.xaxis.set_major_locator(plt.MultipleLocator(np.pi / 2))
ax.xaxis.set_minor_locator(plt.MultipleLocator(np.pi / 4))
fig
def format_func(value, tick_number):
    N = int(np.round(2 * value / np.pi))
    if N == 0:
        return "0"
    elif N == 1:
        return r"$\pi/2$"
    elif N == 2:
        return r"$\pi$"
    elif N % 2 > 0:
        return r"${0}\pi/2$".format(N)
    else:
        return r"${0}\pi$".format(N // 2)
ax.xaxis.set_major_formatter(plt.FuncFormatter(format_func))
fig

3.15.2. Customizing Matplotlib: Configurations and Stylesheets

3.15.2.1. Stylesheets

plt.style.available[:5]
plt.style.use('classic')
def hist_and_lines():
    np.random.seed(0)
fig, ax = plt.subplots(1, 2, figsize=(15, 5))
ax[0].hist(np.random.randn(1000))
for i in range(3):
    ax[1].plot(np.random.rand(20))
    ax[1].legend(['x', 'y', 'z'], loc='lower left')

3.15.3. Three-Dimensional Plotting in Matplotlib

from mpl_toolkits import mplot3d
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = plt.axes(projection='3d')

3.15.3.1. Three-Dimensional Points and Lines

ax = plt.axes(projection='3d')
# Data for a three-dimensional line
zline = np.linspace(0, 25, 2000)
xline = np.sin(zline)
yline = np.cos(zline)
ax.plot3D(xline, yline, zline, 'gray')
# Data for three-dimensional scattered points
zdata = 15 * np.random.random(200)
xdata = np.sin(zdata) + 0.1 * np.random.randn(200)
ydata = np.cos(zdata) + 0.1 * np.random.randn(200)
ax.scatter3D(xdata, ydata, zdata, c=zdata, cmap='Greens')

3.15.3.2. Three-Dimensional Contour Plots

def f(x, y):
    return np.sin(np.sqrt(x ** 2 + y ** 2))
x = np.linspace(-6, 6, 50)
y = np.linspace(-6, 6, 50)
X, Y = np.meshgrid(x, y)
Z = f(X, Y)

fig = plt.figure()
ax = plt.axes(projection='3d')
ax.contour3D(X, Y, Z, 100, cmap='binary')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
ax.view_init(50, 10)
fig

3.15.3.3. Wireframes Plots

fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot_wireframe(X, Y, Z, color='black')
ax.set_title('wireframe')

3.15.3.4. Surface Plots

ax = plt.axes(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
cmap='viridis', edgecolor='none')
ax.set_title('surface')

3.15.3.5. Surface Triangulations

theta = 2 * np.pi * np.random.random(3000)
r = 6 * np.random.random(3000)
x = np.ravel(r * np.sin(theta))
y = np.ravel(r * np.cos(theta))
z = f(x, y)
ax = plt.axes(projection='3d')
ax.scatter(x, y, z, c=z, cmap='viridis', linewidth=0.5)
ax = plt.axes(projection='3d')
ax.plot_trisurf(x, y, z,
cmap='viridis', edgecolor='none')

3.15.4. Geographic Data with Basemap

Use this in order to download the package

#conda install -c conda-forge basemap-data-hires=1.0.8.dev0
#or
#conda install basemap
import os
os.environ['PROJ_LIB'] = r'C:\Users\astro\Anaconda3\pkgs\proj4-5.2.0-ha925a31_1\Library\share'
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
fig = plt.figure(figsize=(8, 8))
m = Basemap(projection='lcc', resolution=None,width=8E6, height=8E6,lat_0=45, lon_0=-100,)
m.etopo(scale=0.5, alpha=0.5)
# Map (long, lat) to (x, y) for plotting
x, y = m(-72.3, 41.8)
plt.plot(x, y, 'ok', markersize=5)
plt.text(x, y, 'UConn', fontsize=12)

3.15.4.1. Map Projections

from itertools import chain
def draw_map(m, scale=0.2):
    m.shadedrelief(scale=scale)
    lats = m.drawparallels(np.linspace(-90, 90, 13))
    lons = m.drawmeridians(np.linspace(-180, 180, 13))
    lat_lines = chain(*(tup[1][0] for tup in lats.items()))
    lon_lines = chain(*(tup[1][0] for tup in lons.items()))
    all_lines = chain(lat_lines, lon_lines)

    for line in all_lines:
        line.set(linestyle='-', alpha=0.3, color='w')
## Cylindrical projections

fig = plt.figure(figsize=(8, 6), edgecolor='w')
m = Basemap(projection='cyl', resolution=None,llcrnrlat=-90, urcrnrlat=90,llcrnrlon=-180, urcrnrlon=180, )
draw_map(m)

More types of projections can be found here: https://matplotlib.org/basemap/users/mapsetup.html

3.15.4.2. Drawing a Map Background

fig, ax = plt.subplots(1, 2, figsize=(12, 8))
for i, res in enumerate(['l', 'h']):
    m = Basemap(projection='gnom', lat_0=57.3, lon_0=-6.2,
    width=90000, height=120000, resolution=res, ax=ax[i])
    m.fillcontinents(color="#FFDDCC", lake_color='#DDEEFF')
    m.drawmapboundary(fill_color="#DDEEFF")
    m.drawcoastlines()
    ax[i].set_title("resolution='{0}'".format(res))

Left side is low resolution and right side is high resolution images.

References:

[1] Jake VanderPlas, Python Data Science Handbook

[2] Matplotlib Basemap Toolkit documentation, https://matplotlib.org/basemap/