Matplotlib 是Python中類似 MATLAB 的繪圖工具,熟悉 MATLAB 也可以很快的上手 Matplotlib。
在任何繪圖之前,我們需要一個Figure對象,可以理解成我們需要一張畫板才能開始繪圖。
import matplotlib.pyplot as plt fig = plt.figure()
在擁有Figure物件之後,在作畫前我們還需要軸,沒有軸的話就沒有繪圖基準,所以需要新增Axes。也可以理解成為真正可以作畫的紙。
fig = plt.figure() ax = fig.add_subplot(111) ax.set(xlim=[0.5, 4.5], ylim=[-2, 8], title='An Example Axes', ylabel='Y-Axis', xlabel='X-Axis') plt.show()
上的程式碼,在一幅圖上新增了一個Axes,然後設定了這個Axes的X軸以及Y軸的取值範圍(這些設定並不是強制的,後面會再談到關於這些設定),效果如下圖:
對於上面的fig.add_subplot(111)
就是添加Axes的,參數的解釋的在畫板的第1行第1列的第一個位置產生一個Axes物件來準備作畫。也可以透過fig.add_subplot(2, 2, 1)
的方式產生Axes,前面兩個參數決定了面板的劃分,例如2, 2會將整個面板分成2 * 2 的方格,第三個參數取值範圍是[1, 2*2] 表示第幾個Axes。如下面的例子:
fig = plt.figure() ax1 = fig.add_subplot(221) ax2 = fig.add_subplot(222) ax3 = fig.add_subplot(224)
可以發現我們上面添加Axes 似乎有點弱雞,所以提供了下面的方式一次性生成所有Axes:
fig, axes = plt.subplots(nrows=2, ncols=2) axes[0,0].set(title='Upper Left') axes[0,1].set(title='Upper Right') axes[1,0].set(title='Lower Left') axes[1,1].set(title='Lower Right')
fig 還是我們熟悉的畫板, axes 成了我們常用二維數組的形式訪問,這在循環繪圖時,額外好用。
相信不少人看過下面的程式碼,很簡單並易懂,但是下面的作畫方式只適合簡單的繪圖,快速的將圖繪出。在處理複雜的繪圖工作時,我們還是需要使用 Axes 來完成作畫的。
plt.plot([1, 2, 3, 4], [10, 20, 25, 30], color='lightblue', linewidth=3) plt.xlim(0.5, 4.5) plt.show()
plot()函數畫出一系列的點,並且用線將它們連接起來。看下例子:
x = np.linspace(0, np.pi) y_sin = np.sin(x) y_cos = np.cos(x) ax1.plot(x, y_sin) ax2.plot(x, y_sin, 'go--', linewidth=2, markersize=12) ax3.plot(x, y_cos, color='red', marker='+', linestyle='dashed')
在上面的三個Axes上作畫。 plot,前面兩個參數為x軸、y軸資料。 ax2的第三個參數是 MATLAB風格的繪圖,對應ax3上的顏色,marker,線型。
另外,我們可以透過關鍵字參數的方式繪圖,如下例:
x = np.linspace(0, 10, 200) data_obj = {'x': x, 'y1': 2 * x + 1, 'y2': 3 * x + 1.2, 'mean': 0.5 * x * np.cos(2*x) + 2.5 * x + 1.1} fig, ax = plt.subplots() #填充两条线之间的颜色 ax.fill_between('x', 'y1', 'y2', color='yellow', data=data_obj) # Plot the "centerline" with `plot` ax.plot('x', 'mean', color='black', data=data_obj) plt.show()
發現上面的作圖,在資料部分只傳入了字串,這些字串對一個這data_obj 中的關鍵字,當以這種方式作畫時,將會在傳入給data 中尋找對應關鍵字的資料來繪圖。
只畫點,但不用線連接起來。
x = np.arange(10) y = np.random.randn(10) plt.scatter(x, y, color='red', marker='+') plt.show()
長條圖分兩種,一種是水平的,一種是垂直的,見下例:
np.random.seed(1) x = np.arange(5) y = np.random.randn(5) fig, axes = plt.subplots(ncols=2, figsize=plt.figaspect(1./2)) vert_bars = axes[0].bar(x, y, color='lightblue', align='center') horiz_bars = axes[1].barh(x, y, color='lightblue', align='center') #在水平或者垂直方向上画线 axes[0].axhline(0, color='gray', linewidth=2) axes[1].axvline(0, color='gray', linewidth=2) plt.show()
長條圖也傳回了一個Artists 數組,對應每個條形,例如上圖Artists 數組的大小為5,我們可以透過這些Artists 對條形圖的樣式進行更改,如下例:
fig, ax = plt.subplots() vert_bars = ax.bar(x, y, color='lightblue', align='center') # We could have also done this with two separate calls to `ax.bar` and numpy boolean indexing. for bar, height in zip(vert_bars, y): if height < 0: bar.set(edgecolor='darkred', color='salmon', linewidth=3) plt.show()
直方圖用於統計資料出現的次數或頻率,有多種參數可以調整,見下例:
np.random.seed(19680801) n_bins = 10 x = np.random.randn(1000, 3) fig, axes = plt.subplots(nrows=2, ncols=2) ax0, ax1, ax2, ax3 = axes.flatten() colors = ['red', 'tan', 'lime'] ax0.hist(x, n_bins, density=True, histtype='bar', color=colors, label=colors) ax0.legend(prop={'size': 10}) ax0.set_title('bars with legend') ax1.hist(x, n_bins, density=True, histtype='barstacked') ax1.set_title('stacked bar') ax2.hist(x, histtype='barstacked', rwidth=0.9) ax3.hist(x[:, 0], rwidth=0.9) ax3.set_title('different sample sizes') fig.tight_layout() plt.show()
參數中density
控制Y軸是機率還是數量,與傳回的第一個的變數對應。 histtype
控制著直方圖的樣式,預設是‘bar’,對於多個條形時就相鄰的方式呈現如子圖1, ‘barstacked’ 就是疊在一起,如子圖2、3。 rwidth
控制寬度,這樣可以空出一些間隙,比較圖2、3. 圖4是只有一條資料時。
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' sizes = [15, 30, 45, 10] explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs') fig1, (ax1, ax2) = plt.subplots(2) ax1.pie(sizes, labels=labels, autopct='%1.1f%%', shadow=True) ax1.axis('equal') ax2.pie(sizes, autopct='%1.2f%%', shadow=True, startangle=90, explode=explode, pctdistance=1.12) ax2.axis('equal') ax2.legend(labels=labels, loc='upper right') plt.show()
餅圖自動依照資料的百分比畫餅。。 labels
是各個區塊的標籤,如子圖一。 autopct=%1.1f%%
表示格式化百分比精確輸出,explode
,突出某些區塊,不同的值突出的效果不一樣。 pctdistance=1.12
百分比距離圓心的距離,預設為0.6.
为了专注于如何画图,省去数据的处理部分。 data 的 shape 为 (n, ), data2 的 shape 为 (n, 3)。
fig, (ax1, ax2) = plt.subplots(2) ax1.boxplot(data) ax2.boxplot(data2, vert=False) #控制方向
散点图的一种,加入了第三个值 s
可以理解成普通散点,画的是二维,泡泡图体现了Z的大小,如下例:
np.random.seed(19680801) N = 50 x = np.random.rand(N) y = np.random.rand(N) colors = np.random.rand(N) area = (30 * np.random.rand(N))**2 # 0 to 15 point radii plt.scatter(x, y, s=area, c=colors, alpha=0.5) plt.show()
有时候需要描绘边界的时候,就会用到轮廓图,机器学习用的决策边界也常用轮廓图来绘画,见下例:
fig, (ax1, ax2) = plt.subplots(2) x = np.arange(-5, 5, 0.1) y = np.arange(-5, 5, 0.1) xx, yy = np.meshgrid(x, y, sparse=True) z = np.sin(xx**2 + yy**2) / (xx**2 + yy**2) ax1.contourf(x, y, z) ax2.contour(x, y, z)
上面画了两个一样的轮廓图,contourf
会填充轮廓线之间的颜色。数据x, y, z通常是具有相同 shape 的二维矩阵。x, y 可以为一维向量,但是必需有 z.shape = (y.n, x.n) ,这里 y.n 和 x.n 分别表示x、y的长度。Z通常表示的是距离X-Y平面的距离,传入X、Y则是控制了绘制等高线的范围。
当绘画完成后,会发现X、Y轴的区间是会自动调整的,并不是跟我们传入的X、Y轴数据中的最值相同。为了调整区间我们使用下面的方式:
ax.set_xlim([xmin, xmax]) #设置X轴的区间 ax.set_ylim([ymin, ymax]) #Y轴区间 ax.axis([xmin, xmax, ymin, ymax]) #X、Y轴区间 ax.set_ylim(bottom=-10) #Y轴下限 ax.set_xlim(right=25) #X轴上限
具体效果见下例:
x = np.linspace(0, 2*np.pi) y = np.sin(x) fig, (ax1, ax2) = plt.subplots(2) ax1.plot(x, y) ax2.plot(x, y) ax2.set_xlim([-1, 6]) ax2.set_ylim([-1, 3]) plt.show()
可以看出修改了区间之后影响了图片显示的效果。
我们如果我们在一个Axes上做多次绘画,那么可能出现分不清哪条线或点所代表的意思。这个时间添加图例说明,就可以解决这个问题了,见下例:
fig, ax = plt.subplots() ax.plot([1, 2, 3, 4], [10, 20, 25, 30], label='Philadelphia') ax.plot([1, 2, 3, 4], [30, 23, 13, 4], label='Boston') ax.scatter([1, 2, 3, 4], [20, 10, 30, 15], label='Point') ax.set(ylabel='Temperature (deg C)', xlabel='Time', title='A tale of two cities') ax.legend() plt.show()
在绘图时传入 label 参数,并最后调用ax.legend()
显示体力说明,对于 legend 还是传入参数,控制图例说明显示的位置:
Location String | Location Code |
---|---|
‘best’ | 0 |
‘upper right’ | 1 |
‘upper left’ | 2 |
‘lower left’ | 3 |
‘lower right’ | 4 |
‘right’ | 5 |
‘center left’ | 6 |
‘center right’ | 7 |
‘lower center’ | 8 |
‘upper center’ | 9 |
‘center’ | 10 |
默认情况下,绘图结束之后,Axes 会自动的控制区间的分段。见下例:
data = [('apples', 2), ('oranges', 3), ('peaches', 1)] fruit, value = zip(*data) fig, (ax1, ax2) = plt.subplots(2) x = np.arange(len(fruit)) ax1.bar(x, value, align='center', color='gray') ax2.bar(x, value, align='center', color='gray') ax2.set(xticks=x, xticklabels=fruit) #ax.tick_params(axis='y', direction='inout', length=10) #修改 ticks 的方向以及长度 plt.show()
上面不仅修改了X轴的区间段,并且修改了显示的信息为文本。
当我们绘画多个子图时,就会有一些美观的问题存在,例如子图之间的间隔,子图与画板的外边间距以及子图的内边距,下面说明这个问题:
fig, axes = plt.subplots(2, 2, figsize=(9, 9)) fig.subplots_adjust(wspace=0.5, hspace=0.3, left=0.125, right=0.9, top=0.9, bottom=0.1) #fig.tight_layout() #自动调整布局,使标题之间不重叠 plt.show()
通过fig.subplots_adjust()
我们修改了子图水平之间的间隔wspace=0.5
,垂直方向上的间距hspace=0.3
,左边距left=0.125
等等,这里数值都是百分比的。以 [0, 1] 为区间,选择left、right、bottom、top 注意 top 和 right 是 0.9 表示上、右边距为百分之10。不确定如果调整的时候,fig.tight_layout()
是一个很好的选择。之前说到了内边距,内边距是子图的,也就是 Axes 对象,所以这样使用 ax.margins(x=0.1, y=0.1)
,当值传入一个值时,表示同时修改水平和垂直方向的内边距。
观察上面的四个子图,可以发现他们的X、Y的区间是一致的,而且这样显示并不美观,所以可以调整使他们使用一样的X、Y轴:
fig, (ax1, ax2) = plt.subplots(1, 2, sharex=True, sharey=True) ax1.plot([1, 2, 3, 4], [1, 2, 3, 4]) ax2.plot([3, 4, 5, 6], [6, 5, 4, 3]) plt.show()
改变边界的位置,去掉四周的边框:
fig, ax = plt.subplots() ax.plot([-2, 2, 3, 4], [-10, 20, 25, 5]) ax.spines['top'].set_visible(False) #顶边界不可见 ax.xaxis.set_ticks_position('bottom') # ticks 的位置为下方,分上下的。 ax.spines['right'].set_visible(False) #右边界不可见 ax.yaxis.set_ticks_position('left') # "outward" # 移动左、下边界离 Axes 10 个距离 #ax.spines['bottom'].set_position(('outward', 10)) #ax.spines['left'].set_position(('outward', 10)) # "data" # 移动左、下边界到 (0, 0) 处相交 ax.spines['bottom'].set_position(('data', 0)) ax.spines['left'].set_position(('data', 0)) # "axes" # 移动边界,按 Axes 的百分比位置 #ax.spines['bottom'].set_position(('axes', 0.75)) #ax.spines['left'].set_position(('axes', 0.3)) plt.show()
以上是Python Matplotlib基礎:常用用法及範例的詳細內容。更多資訊請關注PHP中文網其他相關文章!