前言
matplotlib 提供的所有繪圖都帶有預設樣式。雖然這可以進行快速繪圖,但有時可能需要自定義繪圖的顔色和樣式,以對繪制更加精美、符合審美要求的圖像。matplotlib 的設計考慮到了此需求,很容易調整 matplotlib 圖形的樣式。
控制填充樣式
matplotlib 提供了填充圖案用于填充平面。這些填充圖案,對于僅包含黑白兩色的圖形中具有重要作用。
import numpy as np
import matplotlib.pyplot as plt
n = 10
a = np.random.random(n)
b = np.random.random(n)
x = np.arange(n)
plt.bar(x, a, color='w', hatch='x', edgecolor='black')
plt.bar(x, a+b, bottom=a, color='w', edgecolor='black', hatch='/')
plt.show()

Tips:具有填充呈現性的函數(如 pyplot.bar() )接受可選參數hatch控制填充樣式,此參數的可選值包括:"/", "\", "|", "-", "+", "x", "o", "O","."和"*",每個值對應于不同的填充圖案;edgecolor參數可用于控制圖案填充的顔色。
控制标記樣式
在
《詳解常見統計圖的繪制》中,我們已經了解了如何如何繪制曲線,并明白了曲線是由點之間的連線構成的;此外,散點圖表示資料集中的每個點。而 matplotlib 提供了多種形狀,可以用其他類型的标記替換點的樣式。
标記的指定方式包括以下幾種:
1. 預定義标記:預定義的形狀,表示為 [0, 8] 範圍内的整數或某些預定義的字元串。
2. 頂點清單:值對清單,用作形狀路徑的坐标。
3. 正多邊形:表示 N 邊正多邊形的三元組 (N, 0, angle),其中 angle 為旋轉角度。
4. 星形多邊形:它表示為三元組 (N, 1, angle),代表 N 邊正星形,其中 angle 為旋轉角度。
import numpy as np
import matplotlib.pyplot as plt
a = np.random.standard_normal((100, 2))
a += np.array((-1, -1))
b = np.random.standard_normal((100, 2))
b += np.array((1, 1))
plt.scatter(a[:,0], a[:,1], color = 'm', marker = 'x')
plt.scatter(b[:,0], b[:,1], color = 'c', marker = '^')
plt.show()
Tips:使用marker參數,可以為每個資料集合集合指定不同的标記。
我們已經在
《Matplotlib使用自定義顔色繪制統計圖》中學習了如何在散點圖中為每個點定義不同的顔色,如果我們需要為每個點定義不同樣式該怎麼辦呢?問題在于,與 color 參數不同,marker 參數不接受标記樣式清單作為輸入。是以,我們不能實作 plt.scatter() 的單次調來顯示具有不同标記的多個點集。解決方案是,将每種類型的資料點分隔置不同集合中,并為每個集合單獨調用 pyplot.scatter() 調用:
import numpy as np
import matplotlib.pyplot as plt
label_list = (
b'Iris-setosa',
b'Iris-versicolor',
b'Iris-virginica',
)
colors = ['c','y','m']
def read_label(label):
return label_list.index(label)
data = np.loadtxt('iris.data', delimiter = ',', converters = { 4 : read_label })
marker_set = ('^', 'x', '.')
for i, marker in enumerate(marker_set):
data_subset = np.asarray([x for x in data if x[4] == i])
plt.scatter(data_subset[:,0], data_subset[:,1], color = colors[i], marker = marker)
plt.show()
對于 pyplot.plot(),也可以使用相同的标記參數通路标記樣式。當資料點密集時,每個點都使用标記進行顯示将會導緻圖檔混亂,是以 matplotlib 提供了 markevery 參數,允許每隔 N 個點顯示一個标記:
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(-6, 6, 1024)
y_1 = np.sinc(x)
y_2 = np.sinc(x) + 1
plt.plot(x, y_1, marker = 'x', color = '.75')
plt.plot(x, y_2, marker = 'o', color = 'k', markevery = 64)
plt.show()
控制标記大小
标記的大小可選參數 s 進行控制:
import numpy as np
import matplotlib.pyplot as plt
a = np.random.standard_normal((100, 2))
a += np.array((-1, -1))
b = np.random.standard_normal((100, 2))
b += np.array((1, 1))
plt.scatter(a[:,0], a[:,1], c = 'm', s = 100.)
plt.scatter(b[:,0], b[:,1], c = 'c', s = 25.)
plt.show()
Tips:标記的大小由 plt.scatter() 的參數 s 設定,但應注意它設定的是标記的表面積倍率而非半徑。
plt.scatter() 函數還可以接受清單作為s參數的輸入,其表示每個點對應一個大小:
import numpy as np
import matplotlib.pyplot as plt
m = np.random.standard_normal((1000, 2))
r_list = np.sum(m ** 2, axis = 1)
plt.scatter(m[:, 0], m[:, 1], c = 'w', edgecolor='c', marker = 'o', s = 32. * r_list)
plt.show()
Tips:plt.plot() 函數允許在 markersize (或簡寫為 ms )參數的幫助下更改标記的大小,但是此參數不接受清單作為輸入。
建立自定義标記
雖然 matplotlib 提供了多種标記形狀。但是在某些情況下我們可能仍然找不到适合具體需求的形狀。例如,我們可能希望使用公司徽标等作為形狀。
在 matplotlib 中,将形狀描述為一條路徑——一系列點的連接配接。是以,如果要定義我們自己的标記形狀,必須提供一系列的點:
import numpy as np
import matplotlib.path as mpath
from matplotlib import pyplot as plt
shape_description = [
( 1., 2., mpath.Path.MOVETO),
( 1., 1., mpath.Path.LINETO),
( 2., 1., mpath.Path.LINETO),
( 2., -1., mpath.Path.LINETO),
( 1., -1., mpath.Path.LINETO),
( 1., -2., mpath.Path.LINETO),
(-1., -2., mpath.Path.LINETO),
(-1., -1., mpath.Path.LINETO),
(-2., -1., mpath.Path.LINETO),
(-2., 1., mpath.Path.LINETO),
(-1., 1., mpath.Path.LINETO),
(-1., 2., mpath.Path.LINETO),
( 0., 0., mpath.Path.CLOSEPOLY),
]
u, v, codes = zip(*shape_description)
my_marker = mpath.Path(np.asarray((u, v)).T, codes)
data = np.random.rand(8, 8)
plt.scatter(data[:,0], data[:, 1], c = 'm', marker = my_marker, s = 75)
plt.show()
Tips:所有帶有标記的圖形的 pyplot 函數都有一個可選參數 marker,其參數值可以是預定義的 matplotlib 标記,也可以是自定義的路徑執行個體,路徑對象在 matplotlib.path 子產品中定義。
Path 對象的構造函數将坐标清單和指令清單作為輸入;每個坐标一條指令,使用一個清單将坐标和指令融合在一起,然後将坐标清單和指令傳遞給路徑構造函數,如下所示:
u, v, codes = zip(*shape_description)
my_marker = mpath.Path(np.asarray((u, v)).T, codes)
形狀是通過光标的移動來描述的:
- MOVETO:此指令将光标移動到指定的坐标,并不畫線。
- LINETO:這将在光标目前點和目标點之間繪制直線,并将光标移動至目标點。
- CLOSEPOLY:此指令僅用于關閉路徑,每個形狀都以這條訓示結束。
理論上,任何形狀都是可能的,我們隻需要描述它的路徑。但在實踐中,如果想使用複雜的形狀,最好可以提前進行轉換工作。