前言
我們已經學習了一系列統計圖來描繪兩個變量間的基本關系,同時也學習了如何高度自定義統計的呈現樣式,但是,僅僅使用這些圖形并不足以應對所有場景。例如,我們需要可視化地顯示降雨在各個地區的分布情況。 是以,我們需要更多的實用圖形來表達現實世界的複雜關系。
可視化二維數組的内容
讓我們從最簡單的場景開始,假設我們有一個二維數組——著名的分形形狀 Mandelbrot,我們想将其可視化。
首先需要建立一個二維數組,然後調用 plt.imshow() 将其可視化。
import numpy as np
import matplotlib.cm as cm
from matplotlib import pyplot as plt
def iter_count(c, max_iter):
x = c
for n in range(max_iter):
if abs(x) > 2.:
return n
x = x ** 2 + c
return max_iter
n = 512
max_iter = 64
xmin, xmax, ymin, ymax = -2.2, .8, -1.5, 1.5
x = np.linspace(xmin, xmax, n)
y = np.linspace(ymin, ymax, n)
z = np.empty((n, n))
for i, y_i in enumerate(y):
for j, x_j in enumerate(x):
z[i, j] = iter_count(complex(x_j, y_i), max_iter)
plt.imshow(z, cmap = cm.Spectral)

Tips:imshow() 接受一個 2D 數組作為參數置,用于渲染圖檔,其中每個像素代表一個從 2D 數組中提取的值。像素的顔色從 colormap 中選取。2D 數組中的資料也可以是自檔案或其他源,例如我們完全可以将讀取的圖檔繪制在圖形中。
# 讀取圖檔
img = plt.imread('img.png')
# 繪制圖檔
plt.imshow(img)
我們也可以使用不同的顔色映射觀察效果,隻需要修改 plt.imshow() 可選參數 cmap 的值即可.
plt.imshow(z, cmap = cm.binary, extent=(xmin, xmax, ymin, ymax))
Tips:plt.imshow() 的可選參數 extent 指定存儲在二維數組中的資料的坐标系——由四個值組成的元組,分别表示水準軸和垂直軸上的最小、最大範圍。
接下來,将數組的尺寸由從 512x512 減少到 32x32,看看效果如何:
n = 64
Tips:使用 32x32 的數組表示 Mandelbrot 集時,得到的圖檔的尺寸并沒有縮小,但和 512x512 數組産生的圖檔仍有明顯差别。這是由于,生成一張給定大小的圖檔,如果輸入的資料小于或大于該圖檔尺寸,plt.imshow() 将執行插值操作。預設的插值是線性插值,可以看出效果并不總是理想的。可以通過 imshow() 函數的可選參數 interpolation 指定要使用的插值類型。
使用雙三次插值算法(interpolation = 'bicubic')檢視效果:
二維标量場的可視化
可以使用 numpy.meshgrid() 函數從 2D 函數中生成樣本。然後,使用 plt.pcolormesh() 顯示此函數圖形:
n = 256
x = np.linspace(-3., 3., n)
y = np.linspace(-3., 3., n)
x_list, y_list = np.meshgrid(x, y)
z_list = x_list * np.cos(x_list ** 2 + y_list ** 2)
plt.pcolormesh(x_list, y_list, z_list, cmap = cm.Spectral)
cb = plt.colorbar(orientation='horizontal', shrink=.75)
Tips:使用顔色映射可以幫助我們快速判斷相應點的符号和大小。
np.meshgrid() 函數的作用是:擷取兩個坐标清單,并建構坐标網格。因為兩個坐标清單都是 numpy 數組,是以我們可以以處理單個變量的方式處理它們,這使得計算标量場的過程簡潔易讀。最後,調用函數 plt.pcolormesh() 呈現圖檔。
等高線的可視化
等高線将具有相同值的所有點連接配接起來,可以更容易看到資料的分布特征。
def iter_count(c, max_iter):
x = c
for n in range(max_iter):
if abs(x) > 2.:
return n
x = x ** 2 + 0.98 * c
return max_iter
n = 512
max_iter = 80
xmin, xmax, ymin, ymax = -0.32, -0.22, 0.8, 0.9
x = np.linspace(xmin, xmax, n)
y = np.linspace(ymin, ymax, n)
z = np.empty((n, n))
for i, y_i in enumerate(y):
for j, x_j in enumerate(x):
z[j, i] = iter_count(complex(x_j, y_i), max_iter)
plt.imshow(z, cmap = cm.Spectral,
interpolation = 'bicubic',
origin = 'lower',
extent=(xmin, xmax, ymin, ymax))
levels = [8, 12, 16, 20]
ct = plt.contour(x, y, z, levels, cmap = cm.binary)
plt.clabel(ct, fmt='%d')
Tips:pyplot.contour() 函數擷取樣本網格的坐标清單 x 和 y 以及存儲在矩陣 z 中的值。然後,該函數将渲染在 "level" 清單中指定的值相對應的輪廓,可以使用可選參數 cmap 運用色彩映射進行着色,也可以使用可選參數 color 為所有輪廓指定一種唯一的顔色。
每個輪廓可以用顔色條顯示,也可以直接在圖形上顯示。plt.contour() 函數傳回一個 Contour 執行個體。pyplot.clabel() 函數擷取 contour 執行個體和一個可選的格式字元串來呈現每個等高線的标簽。
Tips:預設情況下,填充輪廓不具抗鋸齒性。可以使用了可選參數 antialiased 來獲得更令人滿意的結果。
ct = plt.contour(x, y, z, levels, cmap = cm.binary, antialiased = True)
二維向量場的可視化
向量場将二維向量與二維平面的每個點相關聯,在實體學中很常見。
本例中,為了進行符号計算,我們借助 SymPy 包,這個軟體包隻用于保持代碼的簡短。如果未安裝此包,可以使用 pip install sympy 指令進行安裝。
我們不必關系向量場的計算方法,記住,本文的主要目的是可視化,是以我們隻需要關心如何顯示向量場——使用 pyplot.quiver() 函數。
import sympy
from sympy.abc import x, y
def cylinder_stream_function(u = 1, r = 1):
radius = sympy.sqrt(x ** 2 + y ** 2)
theta = sympy.atan2(y, x)
return u * (radius - r ** 2 / r) * sympy.sin(theta)
def velocity_field(psi):
u = sympy.lambdify((x, y), psi.diff(y), 'numpy')
v = sympy.lambdify((x, y), -psi.diff(x), 'numpy')
return u, v
u_func, v_func = velocity_field(cylinder_stream_function() )
xmin, xmax, ymin, ymax = -2.5, 2.5, -2.5, 2.5
y, x = np.ogrid[ymin:ymax:16j, xmin:xmax:16j]
u, v = u_func(x, y), v_func(x, y)
m = (x ** 2 + y ** 2) < 1.
u = np.ma.masked_array(u, mask = m)
v = np.ma.masked_array(v, mask = m)
shape = patches.Circle((0, 0), radius = 1., lw = 2., fc = 'w', ec = 'c', zorder = 0)
plt.gca().add_patch(shape)
plt.quiver(x, y, u, v, color='c', zorder = 1)
plt.axes().set_aspect('equal')
Tips:向量場存儲在矩陣 u 和 v 中,我們從向量場中采樣的每個向量的坐标;矩陣 x 和 y 表示樣本位置。矩陣 x、y、u 和 v 被傳遞給 pyplot.quiver(),即可呈現向量場。