零: 深度學習Theory&Code從0到1——先導篇之matplotlib 進階教程)

導論:

在科研和研究的過程中,無論是哪個學科或者將來走上工作崗位,可視化是非常重要的一個環節。

這裡的重要性,在我看來有三點:

  1. 人是視覺動物,老闆看你工作做的怎麼樣,paper reviewer看你的研究做的怎麼樣,有一部分的肯定來自於圖表的合理展示以及對圖表的『故事性』敘述。
  2. 通過對數據的可視化,進一步找到規律,發現問題並解決問題。因為數據都是冷冰冰的,只有把他們組合起來才具有價值。
  3. 針對特定研究領域(如CV,CG),必須在演算法的每一步進行可視化以檢驗演算法的準確性。

以上就是個人對其重要性的理解,其他就不哆嗦了。

本篇文章主要介紹matplotlib的進階教程。基本涵蓋了大部分的使用場景。matplotlib是基於python語言的一個可視化的package,在2D可視化領域還是極其強大的,應該不比R或者matlab的2D繪圖功能差。

Note1: 適合入門級選手,大神請繞道~

Note2:如果研究興趣是圖形學,或者說處理對象是point cloud, mesh等3D對象,歡迎使用亮亮老師的mapple軟體,非常強大。(鏈接如下)

Software & code - Liangliang Nan

順便吐槽一下,matplotlib或者任何其他基於python的package可視化點雲或者面片的效果均不理想,可以嘗試下上面的鏈接,事半功倍。


概述:

下面五幅圖是截取一些以前做research相關的中間圖

其實在二維可視化場景大致分為五大類型(常用的一般都是這五種),上面的五個示意圖除了條形圖未覆蓋其他均有。正文部分根據每個類型以一個完整Simple case +More complicated case 說明。

  1. Line-style 線狀圖
  2. Scatter-style 散點圖
  3. Histograms-style 直方圖
  4. Bar-style 條形圖
  5. Image 圖像

正文:

1. Line-style 線狀圖

(1) Simple case:

非常簡單,平常畫畫函數是綽綽有餘的

先上圖:

2D Line plot(simple)

2D Line plot(simple)

再上代碼:(這個就不注釋了)

import numpy as npimport matplotlib.pyplot as plt# 第一幅圖X = np.linspace(-np.pi, np.pi, 20, endpoint=True)Cos, Sin = np.cos(X), np.sin(X)plt.plot(X,Cos)plt.plot(X,Sin )plt.show()# 第二幅圖n = 256X = np.linspace(-np.pi,np.pi,n,endpoint=True)Y = np.sin(2*X)plt.axes([0.025,0.025,0.95,0.95])plt.plot (X, Y+1, color="blue", alpha=1.00)plt.fill_between(X, 1, Y+1, color="green", alpha=.25)plt.plot (X, Y-1, color="blue", alpha=1.00)plt.fill_between(X, -1, Y-1, (Y-1) > -1, color="blue", alpha=.25)plt.fill_between(X, -1, Y-1, (Y-1) < -1, color="red", alpha=.25)plt.xlim(-np.pi,np.pi), plt.xticks([])plt.ylim(-2.5,2.5), plt.yticks([])plt.show()

(2)More complicated case

標準的畫法,基本的參數設置都有提及。

用的最多的一種形式,可以將多個曲線繪製在同一張fig中,同時可以高度定製線條、坐標軸、網格線、圖例、注釋等等。

先上圖:

2D Line plot(comprehend)

再上代碼:(適當的地方我會給出注釋)

要點:

設置線條:color, linewidth, linestyle, marker, markersize以及後面legend會用到的label

設置坐標軸:主要是label, ticks, lim

設置圖例:主要就是簡單的loc(做右下至左下分別設置為0,1,2,3),以及可以定製的bbox_to_anchor,以及是否frameon。高級用法可以有個handle可以使用(不過一般用不上)

設置網格:只需要調用plt.grid()即可

設置spine: 可以取消可見以及移動到任意位置

設置標註:兩種方式。一是指向data的標註(plt.annotate),另一種是純文本標註(plt.text)

import numpy as npimport matplotlib.pyplot as pltimport osimport sys# 找出當前路徑BASE_DIR = os.path.dirname(os.path.abspath(__file__))# 生成2-D數據X = np.linspace(-np.pi, np.pi, 20, endpoint=True)Cos, Sin = np.cos(X), np.sin(X)# 這裡顯示調用了plt.figure返回一個fig對象, 為了能夠後面保存這個fig對象# 並且設置了fig的大小和每英寸的解析度# 注意: resolution = figsize*dpi(因此這裡的savefig的解析度為1200X900)fig = plt.figure(figsize=(4,3),dpi=300)ax = plt.gca() # gca: get current axis# 調用plt.plot函數將兩條曲線畫在同一個坐標系內,並設置相關的參數# 設置線條參數:設置顏色,線寬,線形,標記,標記大小,圖例標籤等等plt.plot(X, Cos, color="blue", linewidth=1, linestyle="-", marker=">", ms=5, label="cosine")plt.plot(X, Sin, color="red", linewidth=1, linestyle="--", marker="<", ms=5, label="sine")# 設置圖例(legend)# plt.legend(loc="auto", frameon=False) # frameon is flag to draw a frame around the legend# Advanced legendplt.legend(bbox_to_anchor=(0.02, .95), loc=3, borderaxespad=0., frameon=False)# 設置坐標軸的取值範圍(lim)plt.xlim(X.min()*1.1, X.max()*1.1)plt.ylim(-1.2, 1.2)# 設置坐標軸的記號(ticks)plt.xticks(np.linspace(-np.pi, np.pi, 5, endpoint=True), [r"$-pi$", r"$-pi/2$", r"$0$", r"$+pi/2$", r"$+pi$"])plt.yticks([-1, 0, +1], [r"$-1$", r"$0$", r"$+1$"], )# 設置坐標軸的標籤(label)plt.xlabel("x_axis")plt.ylabel("y_axis")# # 打開grid選項# plt.grid()# 移動坐標軸到原點# 先將上方和右方的spine去掉(color設為none即可)# 再將x(y)坐標軸設為下方(左方)的spine,並且移動至原點ax.spines["right"].set_color("none")ax.spines["top"].set_color("none")ax.xaxis.set_ticks_position("bottom")ax.spines["bottom"].set_position(("data",0))ax.yaxis.set_ticks_position("left")ax.spines["left"].set_position(("data",0))# 標註(annotate)# 在x=t處畫虛線,並且把(t, y)這個用plt.scatter的方式標記出來# 在(t, y)處用plt.annotate方法以箭頭的方式做標註。t = 2*np.pi/3plt.plot([t,t], [0, np.cos(t)], color="blue", linewidth=1, linestyle="--")plt.scatter([t], [np.cos(t)], 50, color="blue")plt.annotate(r"$cos(frac{2pi}{3})=frac{sqrt{3}}{2}$", xy=(t, np.cos(t)), xycoords="data", xytext=(-90, -30), textcoords="offset points", fontsize=11, arrowprops=dict(arrowstyle="->", connectionstyle="arc3, rad=.2"))plt.plot([t,t], [0, np.sin(t)], color="red", linewidth=1, linestyle="--")plt.scatter([t], [np.sin(t)], 50, color="red")plt.annotate(r"$sin(frac{2pi}{3})=frac{sqrt{3}}{2}$", xy=(t, np.sin(t)), xycoords="data", xytext=(10, 30), textcoords="offset points", fontsize=11, arrowprops=dict(arrowstyle="->", connectionstyle="arc3, rad=.2"))# 標註(text)plt.text(-2, 0.8, "Annotation with pure text", verticalalignment="bottom", horizontalalignment="right", color="green", fontsize=8, bbox={"facecolor":"red", "alpha":0.4, "pad":2})# # 將figure保存在path# fig_name = os.path.join(BASE_DIR, "figure.jpg")# fig.savefig(fig_name)plt.show()

(3) First Special case:規則化多圖

多圖通常用於橫向或者縱向對比。可以是同類型的也可以是不同類型的。

本例主要用於示例,所以只畫了四個背景色填充的fig。

先上圖:

regular multiple plot

regular multiple plot(without ticks)

再上代碼:

要點:

學會畫多圖,通常有兩種方式:

a. plt.subplot(). 這裡調用函數即可,偏於面向過程的思想

b. fig.add_subplot(). 這裡的fig是plt.figure()出來的實例,偏向面向對象的思想

Note:其實還有一種方式,使用方法為: fig, ax_list = plt.subplot()。目前碰到唯一的缺陷是不能繪製不規則的多圖。(不規則多圖請見(4)Second special case)

完整代碼如下:

import numpy as npimport matplotlib.pyplot as pltimport osimport sys# 第一個圖for i,color in enumerate("rgby"): plt.subplot(221+i, facecolor=color) # facecolor一般用於控制背景色 plt.show()# 第二個圖fig = plt.figure()for i,color in enumerate("rgby"): fig.add_subplot(221+i, facecolor=color) plt.xticks([]) # 用於去掉ticks plt.yticks([]) # 用於去掉ticks plt.show()

(4) Second Special case:不規則化多圖

偶爾也會用到。

先上圖:

irregular multiple plot

irregular multiple plot

再上代碼:

要點:

在調用fig.add_subplot時,要清楚是如何劃分的

import numpy as npimport matplotlib.pyplot as pltimport matplotlib.gridspec as gridspecimport osimport sys# 第一個圖fig = plt.figure()ax1 = fig.add_subplot(121, facecolor="r")ax1.set_xticks([])ax1.set_yticks([])ax2 = fig.add_subplot(222, facecolor="g")ax2.set_xticks([])ax2.set_yticks([])ax3 = fig.add_subplot(224, facecolor="k")ax3.set_xticks([])ax3.set_yticks([])plt.show()# 第二個圖G = gridspec.GridSpec(3, 3)axes_1 = plt.subplot(G[0, :], facecolor="r")plt.xticks([]), plt.yticks([])plt.text(0.5,0.5, "Axes 1",ha="center",va="center",size=24,alpha=.5)axes_2 = plt.subplot(G[1,:-1], facecolor="g")plt.xticks([]), plt.yticks([])plt.text(0.5,0.5, "Axes 2",ha="center",va="center",size=24,alpha=.5)axes_3 = plt.subplot(G[1:, -1], facecolor="b")plt.xticks([]), plt.yticks([])plt.text(0.5,0.5, "Axes 3",ha="center",va="center",size=24,alpha=.5)axes_4 = plt.subplot(G[-1,0], facecolor="y")plt.xticks([]), plt.yticks([])plt.text(0.5,0.5, "Axes 4",ha="center",va="center",size=24,alpha=.5)axes_5 = plt.subplot(G[-1,-2], facecolor="k")plt.xticks([]), plt.yticks([])plt.text(0.5,0.5, "Axes 5",ha="center",va="center",size=24,alpha=.5)plt.show()

=======================(手動分割)=====================

2. Scatter-style 線狀圖

(1) Simple case:

第一幅圖時使用了默認的cmap(應該是Sequential colormaps中的"hot")。第二個為qualitative colormaps中的"Set1"。

具體請參照:

Choosing Colormaps

color example code: colormaps_reference.py

先上圖:

cmap: default

cmap: "Set1"

再上代碼:

import matplotlib.pyplot as pltimport numpy as np# 生成mean=0.0, sigma=1的二維標準正態分布,數據點為1000# 並且採用一個函數生成一個color的一個序列(只是為了好看而已,無須研究)n = 1000normal_2D_data = np.random.normal(0, 1, (n, 2)) T = np.arctan2(normal_2D_data[:, 1],normal_2D_data[:, 0]) # for color value# 調用plt.scatter進行畫圖,第一句採用默認的cmap即第一個圖,第二句採用稱為『Set1』的 cmap即第二個圖# plt.scatter(normal_2D_data[:, 0], normal_2D_data[:, 1], s=75, c=T, alpha=.6)plt.scatter(normal_2D_data[:, 0], normal_2D_data[:, 1], s=75, c=T, alpha=.6, cmap="Set1")plt.xlim(-1.5, 1.5)plt.xticks(()) # ignore xticksplt.ylim(-1.5, 1.5)plt.yticks(()) # ignore yticksplt.show()

(2)More complicated case

標準的畫法,基本的參數設置都有提及

假設我們有五個二維點集p1...p5。我們希望將五個點集用不同的顏色顯示以區分(相當於區分不同的class)

先上圖:

再上代碼:

要點:

區分:本例和(1) Simple case中的第二張圖,可視化出來看似有label是因為生成了一個color的一個序列並且給出了一個qualitative colormap,但是和本例有本質的區別。

核心步驟:是根據label歸一化出一個值,並且根據這個值通過選擇的colormap生成一個color。有兩種方式:

# 方式一import matplotlib.cm as cmimport matplotlib.colors as colorscmap = cm.Set10norm = Normalize(vmin=0, vmax=4) # 假設有5類cmap(norm(0)) # 第1類的color#方式二norm = Normalize(vmin=0, vmax=4) # 假設有5類color_map = cm.ScalarMappable(norm=norm , cmap=cm.Set1)

完整代碼如下:

import numpy as npimport matplotlib.pyplot as pltimport matplotlib.gridspec as gridspecimport matplotlib.cm as cmimport matplotlib.colors as colorsimport osimport sys# 生成數據和標籤n_points=200n_classes = 5plot_with_labels = Truepts = (10-1)*np.random.random(size=(n_points ,2))-1 # 1000 poinrs, range is (1, 10]labels = np.random.randint(0, n_classes, size=pts.shape[0]) # 5 classes, [0, 1, 2, 3, 4]labels_dict = {0: "pts_1", 1: "pts_2", 2: "pts_3", 3: "pots_4", 4: "pts_5"}fig = plt.figure(dpi=120)axe = plt.axes([0.1, 0.1, 0.7, 0.7])# axe = fig.add_subplot(111)if not plot_with_labels: axe.scatter(pts[:, 0], pts[:, 1], s=100, alpha=0.6)else: # # 第一種方法(use: cm.color_map(color_norm(index))) # unique_labels = np.unique(labels) # print(unique_labels) # n_classes = len(unique_labels) # n_classes = n_classes - 1 # color_norm = colors.Normalize(vmin=0, vmax=4) # for class_idx, label in enumerate(unique_labels): # mask = np.where(labels == label)[0] # print("mask len", len(mask)) # axe.scatter(pts[:, 0][mask], pts[:, 1][mask], # s=100, # color=cm.Set1(color_norm(class_idx)), # label=labels_dict[class_idx], # alpha=0.6) # 第二種方法(use: combine cm.ScalarMappable and colors.Normalize) unique_labels = np.unique(labels) print(unique_labels) n_classes = len(unique_labels) n_classes = n_classes - 1 color_norm = colors.Normalize(vmin=0, vmax=4) color_map = cm.ScalarMappable(norm=color_norm, cmap=cm.Set1) for class_idx, label in enumerate(unique_labels): mask = np.where(labels == label)[0] print("mask len", len(mask)) axe.scatter(pts[:, 0][mask], pts[:, 1][mask], s=100, color=color_map.to_rgba(class_idx), label=labels_dict[class_idx], alpha=0.6)plt.legend(bbox_to_anchor=(1.02, .8), loc=3, borderaxespad=0., frameon=True)axe.grid()axe.set_title("Five Class Points Set")# fig_name = os.path.join(BASE_DIR, "figure_1.jpg")# fig.savefig(fig_name)plt.show()

=======================(手動分割)=====================

3. Histogram-style 直方圖

(1) Simple case:

先上圖:

再上代碼:

import matplotlib.pyplot as pltimport numpy as npimport matplotlib.mlab as mlabmu, sigma = 100, 15x = mu + sigma*np.random.randn(100000)n, bins, patches = plt.hist(x, bins=30, histtype="bar", rwidth=0.8, normed=1)print(n, bins, patches)# add a "best fit" liney = mlab.normpdf( bins, mu, sigma)l = plt.plot(bins, y, "r--", linewidth=1)plt.xlabel("Smarts")plt.ylabel("Probability")plt.title(r"$mathrm{Histogram of IQ:} mu=100, sigma=15$")plt.axis([40, 160, 0, 0.03])plt.grid(True)plt.show()

(2)More complicated case

標準的畫法,基本的參數設置都有提及

先上圖:

再上代碼:

要點:

bin的個數,柱狀圖的類型,透明度等

import matplotlib.pyplot as pltimport numpy as npimport matplotlib.mlab as mlabgaussian_numbers_1 = np.random.normal(size=100000)gaussian_numbers_2 = np.random.normal(3, 2, size=100000)n, bins, patches = plt.hist(gaussian_numbers_1, bins=30, histtype="bar", rwidth=0.8, normed=1, color="g", alpha=0.5, label="Gaussian_1")y = mlab.normpdf( bins, 0, 1)l = plt.plot(bins, y, "k--", linewidth=1)n, bins, patches = plt.hist(gaussian_numbers_2, bins=30, histtype="bar", rwidth=0.8, normed=1, color="r", alpha=0.5, label="Gaussian_2")y = mlab.normpdf( bins, 3, 2)l = plt.plot(bins, y, "k--", linewidth=1)plt.title("Gaussian Comparasion Histogram")plt.xlabel("Value")plt.ylabel("Probability")plt.legend(loc="best")plt.show()

=======================(手動分割)=====================

4. Bar-style 條形圖

(1) Simple case:

先上圖:

再上代碼:

import matplotlib.pyplot as pltimport numpy as npx = np.arange(20)y = x**2plt.bar(x, y)plt.xticks(np.arange(20))plt.show()

(2)More complicated case

標準的畫法,基本的參數設置都有提及

先上圖:

再上代碼:

要點:

n = 12X = np.arange(n)Y1 = (1-X/float(n)) * np.random.uniform(0.5,1.0,n)Y2 = (1-X/float(n)) * np.random.uniform(0.5,1.0,n)# plt.axes([0.025,0.025,0.95,0.95])fig = plt.figure(2)plt.bar(X, +Y1, facecolor="#9999ff", edgecolor="white", label="+Y1")plt.bar(X, -Y2, facecolor="#ff9999", edgecolor="white", label="-Y2")for x,y in zip(X,Y1): plt.text(x, y+0.05, "%.2f" % y, ha="center", va= "bottom")for x,y in zip(X,Y2): plt.text(x, -y-0.05, "%.2f" % y, ha="center", va= "top")plt.xlim(-.5,n)plt.ylim(-1.25,+1.25)plt.xticks([])plt.legend()plt.show()

=======================(手動分割)=====================

5. Image 圖像

(1) Simple case:

先上圖:

再上代碼:

import matplotlib.pyplot as pltimport numpy as npdef f(x,y): return (1-x/2+x**5+y**3)*np.exp(-x**2-y**2)n = 10x = np.linspace(-3,3,3.5*n)y = np.linspace(-3,3,3.0*n)X,Y = np.meshgrid(x,y)Z = f(X,Y)plt.axes([0.025,0.025,0.95,0.95])plt.imshow(Z,interpolation="nearest", cmap="bone", origin="lower")plt.colorbar(shrink=.92)plt.xticks([]), plt.yticks([])# savefig("../figures/imshow_ex.png", dpi=48)plt.show()

(2)More complicated case

先上圖:

再上代碼:

要點:

這裡是一個用於可視化模板匹配的結果。有模板,原圖,熱度圖,此外還有colorbar。

fig = plt.figure() # the same as plt.subplot() or plt.subplot()==> return fig and a tuple of axis ax1 = fig.add_subplot(221) ax1.imshow(T)ax1.set_title("Tempalte")ax1.axis("off") ax2 = fig.add_subplot(222) ax2.imshow(I)ax2.set_title("Result with bbox")ax2.axis("off")ax3 = fig.add_subplot(224) cax = ax3.imshow(heatmap, cmap=cm.jet)ax3.set_title("Heatmap")ax3.axis("off") ax4 = fig.add_subplot(223) ax4.axis("off")# Add colorbar, make sure to specify tick locations to match desired ticklabelscbar = fig.colorbar(cax, ax=ax4, orientation="vertical", ticks=[0, np.max(heatmap)], shrink=0.6)cbar.ax.set_yticklabels(["0", str(np.max(heatmap))]) # vertically oriented colorbar# fig.colorbar(cax, ax=ax[2])plt.suptitle("Method: "+similarity_method)plt.show()

=======================(手動分割)=====================

好了,該完結了。有空再增加點三維可視化的東西。最後給大家推薦一個除了matplotlib之外的一個非常好用的packages:plotly(鏈接如下)

==》 plotly

這篇博文算是這段時間經常用matplotlib的一個總結和再學習,同時也希望能夠幫助入門同志們學習和使用(對,是入門級,如果是大神請直接再看一遍找找問題哈哈哈),如果有什麼問題,歡迎在評論區交流


推薦閱讀:

一行Python代碼能做什麼?
用 Python 怎樣實現一個九九乘法表?
如何用python畫一朵花?
學Python web開發框架到什麼程度可以找到開發的工作?
print or plan and not print()()() 的疑問?

TAG:Python | 数据可视化 | 深度学习DeepLearning |