Matplotlib数据可视化高级
目錄
- 前言
- 1.多圖布局
- 1.1 子視圖
- 1.2 嵌套
- 1.3 多圖布局分格顯示
- 1.3.1 均勻布局
- 1.3.2 不均勻分布
- 1.4 雙軸顯示
- 2.文本、注釋、箭頭
- 2.1 文本
- 2.2 箭頭
- 2.3 注釋
- 2.4 注釋箭頭連接形狀
- 3.訓練場
- 3.1 繪制如下子圖
前言
本文其實屬于:Python的進階之道【AIoT階段一】的一部分內容,本篇把這部分內容單獨截取出來,方便大家的觀看,本文介紹Matplotlib數據可視化高級,讀本文之前,如果沒有 Matplotlib基礎建議先看博客:Matplotlib數據可視化入門,后續還會單獨發一篇 Matplotlib數據可視化進階 內容供讀者學習。
🌟 學習本文之前,需要先自修:NumPy從入門到進階,pandas從入門到進階本文中很多的操作在 NumPy從入門到進階 ,pandas從入門到進階二文中有詳細的介紹,包含一些軟件以及擴展庫,圖片的安裝和下載流程,本文會直接進行使用。
下載 MatplotlibMatplotlibMatplotlib 見博客:matplotlib的安裝教程以及簡單調用,這里不再贅述
1.多圖布局
1.1 子視圖
🚩創建子視圖可以一個視圖一個視圖的創建,也可以多個視圖一起創建:
單圖創建:
多圖一起創建:
# 一次創造多個視圖 fig, axes = plt.subplots(2, 2) # 2行2列:四個圖 # 索引從0開始 axes[0, 0].plot(x, np.sin(x), color = 'red') axes[0, 1].plot(x, np.sin(x), color = 'green') axes[1, 0].plot(x, np.cos(x), color = 'purple') axes[1, 1].plot(x, np.cos(x))
下面附上一個完整的代碼供讀者理解:
遇到無法理解的地方可以看后面的代碼解釋,還是不理解的地方可以評論區留言(有問必答)
對上述代碼的部分進行講解:
ax.plot(x, -y)其實就是返回了一句話:[<matplotlib.lines.Line2D at 0x1914fb1d250>]
我們可以發現這句話使用的是列表,我們取出這句話可以用:
我們也可以使用 , 去取:
還有一個很容易暈掉的細節:就是我們在繪圖的時候幾行幾列第幾個是什么意識:
我們就拿上述代碼去說明:
我們假想有一塊空白的板子是供我們繪圖的,下面來看上述代碼:
這行代碼的意思是把我們假想的這塊白板,劃分稱為兩行兩列的板子:
然后這個圖片占據的是第一個板子的位置,對于板子位置我們有如下規定:
板子的編號從1開始,而非從0開始,從左至右,從上至下依次命名板子
所以對上面這個板子,板子的編號為:
所以我們最后圖像所顯示的其實就是左上角的位置。
接著來看我們的第二個圖:
ax = plt.subplot(2, 2, 2) # 兩行兩列第二個子視圖這下就好理解啦,還是把之前的空白板子分成兩行兩列,然后編號為2,即右上角。
接著我們來看第三個圖:
ax = plt.subplot(2, 1, 2) # 兩行一列第二行視圖把我們的空白板子分成兩行一列,那么就是下圖的形式:
然后我們把第三個圖片放到第二個位置,不難想到,該圖的第二個位置其實就是對應的我們分成兩行兩列的 3,4 位置,所以三個圖像最終繪制的結果就是:
1.2 嵌套
🚩所謂嵌套,其實就是在圖形中繼續畫圖:
import numpy as np import matplotlib.pyplot as pltx = np.linspace(-np.pi, np.pi, 25) y = np.sin(x) fig = plt.figure(figsize = (9, 6)) # 創建視圖plt.plot(x,y)# 嵌套方式一,axes軸域(橫縱坐標范圍),子視圖 # x,y,width,height ax = plt.axes([0.2, 0.55, 0.3, 0.3]) # 參數含義[left, bottom, width, height] ax.plot(x, y, color = 'g')# 嵌套方式二 ax = fig.add_axes([0.55, 0.2, 0.3, 0.3]) # 使用視圖對象添加子視圖 ax.plot(x, y, color = 'r')1.3 多圖布局分格顯示
1.3.1 均勻布局
🚩每張圖片都是均勻展示的
import numpy as np import matplotlib.pyplot as plt x = np.linspace(0,2*np.pi) # sharex:所有小圖共享x軸 sharey:表示所有小圖共享y軸 坐標軸以所有小圖中范圍最大的進行顯示 fig, ((ax11,ax12,ax13), (ax21,ax22,ax23),(ax31,ax32,ax33)) = plt.subplots(3, 3) # 也可通過plt.subplot() 一個個添加子視圖 fig.set_figwidth(9) fig.set_figheight(6) ax11.plot(x,np.sin(x)) ax12.plot(x,np.cos(x)) ax13.plot(x,np.tanh(x)) ax21.plot(x,np.tan(x)) ax22.plot(x,np.cosh(x)) ax23.plot(x,np.sinh(x)) ax31.plot(x,np.sin(x) + np.cos(x)) ax32.plot(x,np.sin(x * x) + np.cos(x * x)) ax33.plot(x,np.sin(x) * np.cos(x)) # 緊湊顯示,邊框會比較小,可以注釋掉該行查看效果 plt.tight_layout() plt.show()1.3.2 不均勻分布
🚩上圖中代碼運行所展示的就是均勻分布的結果,可以看出每張圖片所占的空間大小都是均等的,如下面圖片的展示結果,就是不均勻分布:
為顯示如上圖的不均勻分布,我們有三種方法
方法一:
import numpy as np import matplotlib.pyplot as plt # 需要導入gridspec模塊 x = np.linspace(0, 2 * np.pi, 200) fig = plt.figure(figsize = (12, 9)) # 使用切片方式設置子視圖 ax1 = plt.subplot(3, 1, 1) # 視圖對象添加子視圖 ax1.plot(x, np.sin(10 * x)) # 設置ax1的標題,xlim、ylim、xlabel、ylabel等所有屬性現在只能通過set_屬性名的方法設置 ax1.set_title('ax1_title') # 設置小圖的標題 ax2 = plt.subplot(3, 3, (4, 5)) ax2.set_facecolor('green') ax2.plot(x, np.cos(x),color = 'red') ax3 = plt.subplot(3, 3, (6, 9)) ax3.plot(x,np.sin(x) + np.cos(x)) ax4 = plt.subplot(3, 3, 7) ax4.plot([1, 3], [2, 4]) ax5 = plt.subplot(3, 3, 8) ax5.scatter([1, 2, 3], [0, 2, 4]) ax5.set_xlabel('ax5_x',fontsize = 12) ax5.set_ylabel('ax5_y',fontsize = 12) plt.show()方法二:
import numpy as np import matplotlib.pyplot as pltx = np.linspace(0, 2 * np.pi, 100) plt.figure(figsize = (12, 9)) # 子視圖1 ax1 = plt.subplot2grid(shape = (3, 3),# 布局形狀loc = (0, 0), # 布局繪制位置colspan = 3) # 跨幾列 ax1.plot(x, np.sin(10 * x)) # 設置ax1的標題,xlim、ylim、xlabel、ylabel等所有屬性現在只能通過set_屬性名的方法設置 ax1.set_title('ax1_title') # 設置小圖的標題 # 子視圖2 ax2 = plt.subplot2grid((3, 3), (1, 0), colspan = 2) # 跨兩列 ax2.set_facecolor('green') ax2.plot(x,np.cos(x),color = 'red') # 子視圖3 ax3 = plt.subplot2grid((3, 3), (1, 2), rowspan = 2) # 跨兩行 ax3.plot(x,np.sin(x) + np.cos(x)) # 子視圖4 ax4 = plt.subplot2grid((3, 3), (2, 0)) ax4.plot([1, 3], [2, 4]) # 子視圖5 ax5 = plt.subplot2grid((3, 3), (2, 1)) ax5.scatter([1, 2, 3], [0, 2, 4]) ax5.set_xlabel('ax5_x',fontsize = 12) ax5.set_ylabel('ax5_y',fontsize = 12)
方法三:
1.4 雙軸顯示
🚩有時候,有兩個軸是不夠用的,我們經常會見到如下的圖形,下述圖形的樣式就是雙軸顯示:
就比如我們在繪制正弦波和指數函數的時候,讓他們在一個 yyy軸上顯示是不合理的:
所以,這個時候就需要我們的雙軸顯示:
坐標是雖然是自適應的,但是我們也可以對其進行調整:
2.文本、注釋、箭頭
🚩常用函數如下:
| text() | mpl.axes.Axes.text() | 在Axes對象的任意位置添加文字 |
| xlabel() | mpl.axes.Axes.set_xlabel() | 為X軸添加標簽 |
| ylabel() | mpl.axes.Axes.set_ylabel() | 為Y軸添加標簽 |
| title() | mpl.axes.Axes.set_title() | 為Axes對象添加標題 |
| legend() | mpl.axes.Axes.legend() | 為Axes對象添加圖例 |
| annnotate() | mpl.axes.Axes.annotate() | 為Axes對象添加注釋(箭頭可選) |
| figtext() | mpl.figure.Figure.text() | 在Figure對象的任意位置添加文字 |
| suptitle() | mpl.figure.Figure.suptitle() | 為Figure對象添加中心化的標題 |
2.1 文本
import numpy as np import matplotlib.pyplot as plt# 字體屬性 font = {'fontsize': 20,'family': 'KaiTi','color': 'red','weight': 'bold'} # bold表示字體加粗x = np.linspace(0.0, 5.0, 100) y = np.cos(2 * np.pi * x) * np.exp(-x)plt.figure(figsize = (9, 6)) plt.plot(x, y, 'k') # k代表黑色# 視圖的標題 plt.title('exponential decay', fontdict = font, pad = 20)# figure的大標題 plt.suptitle('指數衰減', y = 1.05, fontdict = font, fontsize = 30)# 向圖片中繪制文本 plt.text(x = 2, y = 0.65, # 橫縱坐標位置s = r'$\cos(2 \pi t) \exp(-t)$', # 文本內容fontsize = 25) # 文本大小plt.xlabel('time (s)') plt.ylabel('voltage (mV)') plt.show()2.2 箭頭
import matplotlib.pyplot as plt import numpy# 隨機生成數字,10行2列(x,y) loc = np.random.randint(0, 10,size = (10, 2)) plt.figure(figsize=(10, 10))# 畫圖: loc[:, 0]:所有行都獲取,索引0--->橫坐標 # loc[:, 1]:所有行都獲取,索引1--->縱坐標 # g*:g代表的是綠色,*代表的是點的形狀是五角星 # ms = 20:點的大小 plt.plot(loc[:, 0], loc[:, 1], 'g*', ms = 20) plt.grid(True)# 路徑 way = np.arange(10) # 0、1、2、...、9索引 np.random.shuffle(way) # 洗牌,打亂順序# 開始連點:0-->1-->2-->...-->9 # for 循環:少一個:10個點連9條線 for i in range(0, len(way) - 1):start = loc[way[i]] # 起點end = loc[way[i + 1]] # 終點# 畫箭頭:plt.arrow(start[0], start[1], # x = start[0], y = start[1]:起點的(x, y)end[0] - start[0], # 水平方向上移動的距離end[1] - start[1], # 豎直方向上移動的距離head_width = 0.2, lw = 2,# 箭頭長度,箭尾線寬length_includes_head = True) # 長度計算包含箭頭箭尾# 繪制編號:0 1 2 3... 8plt.text(start[0], start[1], s = i, fontsize = 18, color = 'red')# 繪制編號:9if i == len(way) - 2:plt.text(end[0], end[1], s = i + 1, fontsize = 18, color = 'red')2.3 注釋
import numpy as np import matplotlib.pyplot as plt# 數據創建 fig, ax = plt.subplots() x = np.arange(0.0, 5.0, 0.01) y = np.cos(2 * np.pi * x) line, = ax.plot(x, y, lw = 2)# 注釋: ax.annotate('local max', # 文本內容xy = (2, 1), # 箭頭指向位置xytext = (3, 1.5), # 文本位置# 箭頭屬性arrowprops = dict(facecolor = 'black', # 箭頭的顏色shrink = 0.05)) # 箭頭兩端收縮的百分比(占總長) ax.annotate('local min',xy = (2.5, -1),xytext = (4, -1.8),arrowprops = dict(facecolor = 'black',width = 2, # 箭頭寬度headwidth = 10, # 箭頭頭部寬度headlength = 10, # 箭頭頭部長度shrink = 0.1)) # 箭頭兩端收縮的百分比(占總長) ax.annotate('median',xy = (2.25, 0),xytext = (0.5, -1.8),arrowprops = dict(arrowstyle = '-|>'), # 箭頭樣式# 按下 Shift+Tab查看提示:-|>:head_length=0.4,head_width=0.2fontsize = 20)# y軸范圍調為(-2, 2) ax.set_ylim(-2, 2)2.4 注釋箭頭連接形狀
import matplotlib.pyplot as pltdef annotate_con_style(ax, connectionstyle):x1, y1 = 3,2x2, y2 = 8,6ax.plot([x1, x2], [y1, y2], ".")ax.annotate(text = '',xy = (x1, y1), # 相當于B點,arrow headxytext = (x2, y2), # 相當于A點,arrow tailarrowprops = dict(arrowstyle = '->', color = 'red',shrinkA = 5,shrinkB = 5,connectionstyle = connectionstyle))ax.text(.05, 0.95, connectionstyle.replace(",", "\n"),transform = ax.transAxes, # 相對坐標ha = "left", va = "top") # 指定對齊方式# 常用箭頭連接樣式 fig, axs = plt.subplots(3, 5, figsize = (9, 6)) annotate_con_style(axs[0, 0], "angle3,angleA=90,angleB=0") annotate_con_style(axs[1, 0], "angle3,angleA=0,angleB=90") annotate_con_style(axs[2, 0], "angle3,angleA = 0,angleB=150") annotate_con_style(axs[0, 1], "arc3,rad=0.") annotate_con_style(axs[1, 1], "arc3,rad=0.3") annotate_con_style(axs[2, 1], "arc3,rad=-0.3") annotate_con_style(axs[0, 2], "angle,angleA=-90,angleB=180,rad=0") annotate_con_style(axs[1, 2], "angle,angleA=-90,angleB=180,rad=5") annotate_con_style(axs[2, 2], "angle,angleA=-90,angleB=10,rad=5") annotate_con_style(axs[0, 3], "arc,angleA=-90,angleB=0,armA=30,armB=30,rad=0") annotate_con_style(axs[1, 3], "arc,angleA=-90,angleB=0,armA=30,armB=30,rad=5") annotate_con_style(axs[2, 3], "arc,angleA=-90,angleB=0,armA=0,armB=40,rad=0") annotate_con_style(axs[0, 4], "bar,fraction=0.3") annotate_con_style(axs[1, 4], "bar,fraction=-0.3") annotate_con_style(axs[2, 4], "bar,angle=180,fraction=-0.2")for ax in axs.flat:# 設置軸域刻度ax.set(xlim = (0, 10), ylim = (0, 10), xticks = [], yticks = [], aspect = 1) fig.tight_layout(pad = 0.2)3.訓練場
3.1 繪制如下子圖
要求:
- 設置中文字體并設置字體大小
- 分別計算每個城市年份、季度、月份、小時的PM2.5數據
- 會用到分組求平均值操作
- 進行數據重塑
- 根據需要調整行索引或者列索引
- 創建子視圖2行2列
- 向子視圖分別繪制年份、季度、月份、小時的各城市PM2.5走勢數據
- 根據需要設置坐標軸標簽(比如月份、小時)
首先我們需要下載一個 Excel 文件:
鏈接: https://pan.baidu.com/s/1nSw6wbOEg8GpP19WQ7ggxw?pwd=53ph
提取碼: 53ph
下載完成之后,把該文件和我們的代碼放到同一個文件夾下,這一操作我們在之前的博客中已經反復說到,這里就不再進行演示
注:代碼處于運行中將顯示:
下列代碼運行幾十秒甚至幾分鐘都是正常的,耐心等待運行結果即可。
我們先來加載我們的數據
%%time import numpy as np import pandas as pd import matplotlib.pyplot as pltplt.rcParams['font.family'] = 'KaiTi' plt.rcParams['font.size'] = 18 df = pd.read_excel('./PM2.5.xlsx')接下來繪制年份的數據:
# 添加子視圖 fig, axes = plt.subplots(2, 2, figsize = (16, 12))# 按照城市年份分組,獲取PM2.5,計算平均值并保留2位小數 df2 = df.groupby(by = ['城市', '年份'])[['PM2.5']].mean().round(2)# 數據重塑 df2 = df2.unstack(level = 0) # 城市作為列索引 df2.columns = df2.columns.droplevel(0) # 刪除 PM2.5 這個列索引 df2 = df2[['北京', '上海', '廣州', '沈陽', '成都']] # 調整列索引的順序 df2.plot(ax = axes[0, 0]) # 左上角
繪制季度:
繪制月份:
繪制小時:
df5 = df.groupby(by = ['城市', '小時'])[['PM2.5']].mean().round(2) # 數據重塑 df5 = df5.unstack(level = 0) df5.columns = df5.columns.droplevel(0) df5 = df5[['北京', '上海', '廣州', '沈陽', '成都']] ax = df5.plot(ax = axes[1, 1]) _ = ax.set_xticks(np.arange(0, 24))最后我們來保存我們的圖片:
plt.savefig('./homework7.png')總結
以上是生活随笔為你收集整理的Matplotlib数据可视化高级的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WPAN、WLAN、WMAN、WWAN、
- 下一篇: 省市区三级行政区数据获取和GeoJson