文章目錄
Python爲數據展示提供了大量優秀的功能包,其中Matplotlib和Pygal是兩個極具代表性的功能包。
一、使用Matplotlib生成數據圖
Matplotlib是一個非常優秀的Python 2D 繪圖庫,只要給出符合格式的數據,通過Matplotlib就可以方便地製作折線圖、柱狀圖、散點圖等各種高質量的數據圖。
(一)、安裝Matplotlib包
pip安裝
pip install matplotlib
(二)Matplotlib數據圖入門
Matplotlib的用法非常簡單,對於最簡單的折線圖來說, 程序只需根據需要給出對應的X 軸、Y 軸數據, 調用pyplot 子模塊下的plot()函數即可生成簡單的折線圖。
示例
import matplotlib.pyplot as plt
# 定義兩個列表分別作爲X軸、Y軸數據
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
# 第一個列表代波啊橫座標的值,第二個列表代表縱座標的值
plt.plot(x_data, y_data)
# 調用show()函數顯示圖形
plt.show()
運行效果:
如果在調用plot()函數時只傳入一個list列表,則該列表的數據將作爲y軸數據,Matplotlib會自動使用0, 1, 2, 3作爲X軸數據。
效果如下圖
plot()函數除了支持創建具有單挑折線的折線圖,也支持創建包含多條折線的複式折線圖,只要在調用plot()函數時傳入多個分別代表x軸和y軸數據的list列表即可。
示例
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定義兩個列表分別作爲兩條折線的Y軸數據
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data1 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 傳入兩組分別代表X軸,Y軸的數據的list列表
plt.plot(x_data, y_data, x_data, y_data1)
# 調用show()函數顯示圖形
plt.show()
運行效果:
也可以將以上代碼中的 `` plt.plot(x_data, y_data, x_data, y_data1) ```改爲多次調用plot()的方式:
plt.plot(x_data, y_data)
plt.plot(x_data, y_data1)
同樣可以在調用plot()函數時傳入額外的參數來指定折線的樣子、如線寬、顏色、樣式等。
示例
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定義兩個列表分別作爲兩條折線的Y軸數據
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data1 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 指定折線的顏色、線寬和樣式
plt.plot(x_data, y_data, color='red', linewidth=2.0, linestyle='--')
plt.plot(x_data, y_data1, color='blue', linewidth=3.0, linestyle='-.')
# 調用show()函數顯示圖形
plt.show()
運行效果:
樣式字符串支持如下參數值:
參數值 | 描述 |
---|---|
- | 代表實線,默認值 |
– | 代表虛線 |
: | 代表點線 |
-. | 代表短線、點相間的虛線 |
(三)管理圖例
可以通過legend()函數來爲折線添加圖例,爲該函數傳入兩個list參數,其中第一個list參數(handles參數)用於引用折線圖上的每條折線,第二個list參數(labels)代表爲每條折線所添加的圖例。
示例
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定義兩個列表分別作爲兩條折線的Y軸數據
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data1 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 指定折線的顏色、線寬和樣式
ln1, = plt.plot(x_data, y_data, color='red', linewidth=2.0, linestyle='--')
ln2, = plt.plot(x_data, y_data1, color='blue', linewidth=3.0, linestyle='-.')
# 調用legend()函數設置圖例
plt.legend(handles=[ln2, ln1],
labels=['示例2年銷售量', '示例1年銷售量'],
loc='lower right')
# 調用show()函數顯示圖形
plt.show()
運行效果:
以上代碼中的loc參數指定圖例添加位置,該參數支持如下參數值:
參數值 | 描述 |
---|---|
best | 自動選擇最佳位置 |
upper right | 將圖例放在右上角 |
upper left | 將圖例放在左上角 |
lower left | 將圖例放在左下角 |
lower right | 將圖例放在右下角 |
right | 將圖例放在右邊 |
center left | 將圖例放在左邊居中的位置 |
center right | 將圖例放在右邊居中的位置 |
lower center | 將圖例放在底部居中的位置 |
upper center | 將圖例放在頂部居中的位置 |
center | 將圖例放在中心 |
中文亂碼解決方案
① 使用matplotlib.font_manager子模塊下的FontProperties類加載中文字體。
② 在調用legend()函數時通過prop屬性指定使用中文字體。
示例
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定義兩個列表分別作爲兩條折線的Y軸數據
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data1 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 指定折線的顏色、線寬和樣式
ln1, = plt.plot(x_data, y_data, color='red', linewidth=2.0, linestyle='--')
ln2, = plt.plot(x_data, y_data1, color='blue', linewidth=3.0, linestyle='-.')
# 使用Matplotlib的字體管理器加載中文字體
my_font = fm.FontProperties(fname="C:\Windows\Fonts\msyh.ttc")
# 調用legend()函數設置圖例
plt.legend(handles=[ln2, ln1],
labels=['示例2年銷售量', '示例1年銷售量'],
loc='lower right',
prop=my_font)
# 調用show()函數顯示圖形
plt.show()
運行效果:
以上程序使用FontProperties類加載c:\windows\Fonts\msyh.ttc文件所對應的中文字體。
legend()函數可以不指定handles參數,只傳入labels參數,這樣該labels參數將按順序爲直線圖中的多條折線添加圖例。
Matplotlib也允許在調用plot()函數時爲每條折線分別傳入label參數,這樣程序在調用legend()函數時就無須傳入labels、handles參數了。
永久改變Matplotlib的默認字體
在Python的交互解釋器中輸入如下命令:
編輯配置文件,找到如下行:
將此行代碼修改爲如下形式,並去掉前面的#號:
(四)管理座標軸
可以調用xlable()和ylabel()函數分別設置X軸、Y軸的名稱,也可以通過title()函數設置整個數據圖的標題,還可以調用xticks()、yticks()函數分別改變X軸、Y軸的刻度值(允許使用文本作爲刻度值)。
示例
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定義兩個列表分別作爲兩條折線的Y軸數據
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data1 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 指定折線的顏色、線寬和樣式
plt.plot(x_data,
y_data,
color='red',
linewidth=2.0,
linestyle='--',
label='圖例1年銷量')
plt.plot(x_data,
y_data1,
color='blue',
linewidth=3.0,
linestyle='-.',
label='圖例2年銷量')
# 調用legend()函數設置圖例
plt.legend(loc='best')
# 設置兩個座標軸的名稱
plt.xlabel("年份")
plt.ylabel("銷量")
# 設置數據圖的標題
plt.title("歷年銷量圖")
# 設置Y軸上的數值文本
# 第一個參數是點的位置,第二個參數是點的文字提示
plt.yticks([50000, 70000, 100000], [r'挺好', r'優秀', r'火爆'])
# 調用show()函數顯示圖形
plt.show()
運行效果:
若要對X軸、Y軸進行更細緻的控制,可以調用gca()函數來獲取座標軸信息對象,然後對座標軸進行控制。
示例
import matplotlib.pyplot as plt
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定義兩個列表分別作爲兩條折線的Y軸數據
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data1 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 指定折線的顏色、線寬和樣式
plt.plot(x_data,
y_data,
color='red',
linewidth=2.0,
linestyle='--',
label='圖例1年銷量')
plt.plot(x_data,
y_data1,
color='blue',
linewidth=3.0,
linestyle='-.',
label='圖例2年銷量')
# 調用legend()函數設置圖例
plt.legend(loc='best')
# 設置兩個座標軸的名稱
plt.xlabel("年份")
plt.ylabel("銷量")
# 設置數據圖的標題
plt.title("歷年銷量圖")
# 設置Y軸上的數值文本
# 第一個參數是點的位置,第二個參數是點的文字提示
plt.yticks([50000, 70000, 100000], [r'挺好', r'優秀', r'火爆'])
ax = plt.gca()
# 設置將x軸的刻度值放在底部X軸上
ax.xaxis.set_ticks_position('bottom')
# 設置將Y軸的刻度值放在左邊Y軸上
ax.yaxis.set_ticks_position('left')
# 設置右邊座標軸線的顏色(設置爲none表示不顯示)
ax.spines['right'].set_color('none')
# 設置頂部座標軸線的顏色(設置爲none表示不顯示)
ax.spines['top'].set_color('none')
# 定義底部座標軸線的位置(放在70000數值處)
ax.spines['bottom'].set_position(('data', 70000))
# 調用show()函數顯示圖形
plt.show()
運行效果:
以上代碼中使用plt.gca()獲取了一個AxesSubplot對象,然後調用該對象的xaxis屬性的set_ticks_position()方法設置X軸刻度值的位置。通過spines屬性可以訪問數據圖四周的座標軸線(Spine對象)
(五)管理多個子圖
使用Matplotlib 除可以生成包含多條折線的複式折線圖之外,它還允許在一張數據圖上包含多個子圖。
調用subplot()函數可以創建一個子圖,然後程序就可以在子圖上進行繪製。subplot(nrows, ncols, mdex, **kwargs)函數的時ows 參數指定將數據圖區域分成多少行; ncols 參數指定將數據圖區域分成多少列: index參數指定獲取第幾個區域。
示例
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
# 定義從-pi到pi之間的數據,平均去64個數據點
x_data = np.linspace(-np.pi, np.pi, 64, endpoint=True)
# 將整個figure分成兩行兩列,第三個參數表示將該圖形放在第1個網格中
plt.subplot(2, 2, 1)
# 繪製正弦曲線
plt.plot(x_data, np.sin(x_data))
plt.gca().spines['right'].set_color('none')
plt.gca().spines['top'].set_color('none')
plt.gca().spines['bottom'].set_position(('data', 0))
plt.gca().spines['left'].set_position(('data', 0))
plt.title('正弦曲線')
# 將整個figure分成兩行兩列,並將該圖形房子啊第2個網格中
plt.subplot(222)
# 繪製餘弦曲線
plt.plot(x_data, np.cos(x_data))
plt.gca().spines['right'].set_color('none')
plt.gca().spines['top'].set_color('none')
plt.gca().spines['bottom'].set_position(('data', 0))
plt.gca().spines['left'].set_position(('data', 0))
plt.title('餘弦曲線')
# 將整個figure分成兩行兩列,並將該圖形放在第3個網格中
plt.subplot(223)
# 繪製正切曲線
plt.plot(x_data, np.tan(x_data))
plt.gca().spines['right'].set_color('none')
plt.gca().spines['top'].set_color('none')
plt.gca().spines['bottom'].set_position(('data', 0))
plt.gca().spines['left'].set_position(('data', 0))
plt.title('正切曲線')
plt.show()
運行效果:
還可以讓某個子圖佔用多個網格,例如將以上代碼中的plt.subplot(2, 2, 1)
改爲 plt.subplot(2, 1, 1)
,然後依次修改另外兩個子圖的位置。
還可以使用GridSpec對繪圖區域進行分割。
示例
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
plt.figure()
# 定義從-pi到pi之間的數據,平均去64個數據點
x_data = np.linspace(-np.pi, np.pi, 64, endpoint=True)
# 將繪圖區域分成兩行三列
gs = gridspec.GridSpec(2, 3)
# 指定ax1佔用第一行(0)整行
ax1 = plt.subplot(gs[0, :])
# 指定ax2佔用第二行(1)的第一格(第二個參數0代表)
ax2 = plt.subplot(gs[1, 0])
# 指定ax3佔用第二行(1)的第二、三格(第二個參數用1:3代表)
ax3 = plt.subplot(gs[1, 1:3])
# 繪製正弦曲線
ax1.plot(x_data, np.sin(x_data))
ax1.spines['right'].set_color('none')
ax1.spines['top'].set_color('none')
ax1.spines['bottom'].set_position(('data', 0))
ax1.spines['left'].set_position(('data', 0))
ax1.set_title('正弦曲線')
# 繪製餘弦曲線
ax2.plot(x_data, np.cos(x_data))
ax2.spines['right'].set_color('none')
ax2.spines['top'].set_color('none')
ax2.spines['bottom'].set_position(('data', 0))
ax2.spines['left'].set_position(('data', 0))
ax2.set_title('餘弦曲線')
# 繪製正切曲線
ax3.plot(x_data, np.tan(x_data))
ax3.spines['right'].set_color('none')
ax3.spines['top'].set_color('none')
ax3.spines['bottom'].set_position(('data', 0))
ax3.spines['left'].set_position(('data', 0))
ax3.set_title('正切曲線')
plt.show()
運行效果:
功能豐富的數據圖
(一)餅圖
使用Matplotlib提供的pie() 函數來繪製餅圖。
示例數據表 TIOBE2019年6月編程語言指數排行榜前10名
語言 | 排名 |
---|---|
Java | 15.004% |
C | 13.300% |
Python | 8.530% |
C++ | 7.384% |
Visual Basic.NET | 4.624% |
C# | 4.483% |
JavaScript | 2.716% |
PHP | 2.567% |
SQL | 2.224% |
Assembly language | 1.479% |
餅圖示例
import matplotlib.pyplot as plt
# 準備數據
data = [
0.15004, 0.13300, 0.08530, 0.07384, 0.04624, 0.04483, 0.02716, 0.02567,
0.02224, 0.01479, 0.37689
]
# 準備標籤
labels = [
'Java', 'C', 'Python', 'C++', 'Visual Basic.NET', 'C#', 'JavaScript',
'PHP', 'SQL', 'Assembly language', '其他'
]
# 將排在第3位的語言(Python)分離出來
explode = [0, 0, 0.3, 0, 0, 0, 0, 0, 0, 0, 0]
# 使用自定義顏色
colors = ['red', 'pink', 'magenta', 'purple', 'orange']
# 將橫、縱座標軸標準化處理,保證餅圖是一個正圓,否則爲橢圓
plt.axes(aspect='equal')
# 控制X軸和Y軸的範圍(用於控制餅圖的圓心、半徑)
plt.xlim(0, 8)
plt.ylim(0, 8)
# 繪製餅圖
plt.pie(x=data, # 繪圖數據
labels=labels, # 添加編程語言標籤
explode=explode, # 突出顯示Python
colors=colors, # 設置餅圖的自定義填充色
autopct='%.3f%%', # 設置百分比的格式,此處保留3位小數
pctdistance=0.8, # 設置百分比標籤與圓心的距離
labeldistance=1.05, # 設置標籤與圓心的距離
startangle=180, # 設置餅圖的初始角度
center=(4, 4), # 設置餅圖的圓心(相當於X軸和Y軸的範圍)
radius=3.8, # 設置餅圖的半徑(相當於X軸和Y軸的範圍
counterclock=False, # 是否爲逆時針方向,這裏爲順時針
wedgeprops={
'linewidth': 1,
'edgecolor': 'green'
}, # 設置餅圖內外邊界的屬性值
textprops={
'fontsize': 12,
'color': 'black'
}, # 設置文本標籤的屬性值
frame=1) # 是否顯示餅圖的圓圈,此處設置爲顯示
# 不顯示X軸和Y軸的刻度值
plt.xticks(())
plt.yticks(())
# 添加圖形標題
plt.title('TIOBE2019年6月編程語言指數排行榜前10名')
# 顯示圖形
plt.show()
運行效果:
(二)柱狀圖
使用Matplotlib提供的bar()函數來繪製柱狀圖。與前面介紹的plot()函數類似, 程序每次調用bar()函數時都會生成一組柱狀圖, 如果希望生成多組柱狀圖,則可通過多次調用bar()函數來實現。
示例
import matplotlib.pyplot as plt
# 構建數據
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 繪圖
plt.bar(x=x_data, height=y_data, label='產品1', color='steelblue', alpha=0.8)
plt.bar(x=x_data, height=y_data2, label='產品2', color='indianred', alpha=0.8)
# 在柱狀圖上顯示具體數值,ha參數控制水平對齊方式,va參數控制垂直對齊方式
for x, y in enumerate(y_data):
plt.text(x, y + 100, '%s' % y, ha='center', va='bottom')
for x, y in enumerate(y_data2):
plt.text(x, y + 100, '%s' % y, ha='center', va='top')
# 設置標題
plt.title("產品對比")
# 爲兩個座標軸設置名稱
plt.xlabel("年份")
plt.ylabel("銷量")
# 顯示圖例
plt.legend()
plt.show()
運行效果:
使用bar()函數繪製柱狀圖時,默認不會在柱狀圖上顯示具體的數值。程序可以通過調用text()函數在數據圖上輸出文字。text()函數前兩個參數控制輸出文字的X、Y座標,第三個參數控制輸出的內容,va控制文字的垂直對齊方式,ha控制文字的水平對齊方式。
如果不希望兩組數據重疊在一起,那麼就需要對X軸進行設置,因爲兩組柱狀圖使用的是同一組list列表數據,爲了將多個柱狀圖的條柱並列顯示,程序需要爲這些柱狀圖重新計算不同的X軸數據。爲了精確控制條柱的寬度,程序可以在調用bar()函數時傳入width參數,這樣可以更好地計算條柱的並列方式。
示例
import matplotlib.pyplot as plt
import numpy as np
# 構建數據
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
bar_width = 0.3
# 將X軸數據改爲使用range(len(x_data)),就是0、1、2……
plt.bar(x=range(len(x_data)),
height=y_data,
label='產品1',
color='steelblue',
alpha=0.8,
width=bar_width)
# 將X軸數據改爲使用np.arange(len(x_data)) + bar_width
# 就是bar_width、1 + bar_width、2 + bar_width……這樣就和第一個圖並列了
plt.bar(x=np.arange(len(x_data)) + bar_width,
height=y_data2,
label='產品2',
color='indianred',
alpha=0.8,
width=bar_width)
# 在柱狀圖上顯示具體的數值,ha參數控制水平對齊方式,va參數控制垂直對齊方式
for x, y in enumerate(y_data):
plt.text(x, y + 100, '%s' % y, ha='center', va='bottom')
for x, y in enumerate(y_data2):
plt.text(x + bar_width, y + 100, '%s' % y, ha='center', va='top')
# 設置標題
plt.title('產品對比')
# 爲兩個座標軸設置名稱
plt.xlabel("年份")
plt.ylabel("銷量")
# 顯示圖例
plt.legend()
plt.show()
運行效果:
以上程序有一個不足之處,就是X軸的刻度值變成了0,1,2……而不再顯示年份,爲了讓柱狀圖的X軸刻度顯示年份,可以調用xticks()函數重新設置X軸的刻度值。如:
plt.xticks(np.arange(len(x_data)) + bar_width/2, x_data)
(三)水平柱狀圖
調用Matplotlib的barh()函數可以生成水平柱狀圖。barh()函數的用法與bar()函數的用法基本一樣,只是在調用barh()函數時使用y 參數傳入Y 軸數據,使用width 參數傳入代表條柱寬度的數據。
示例
import matplotlib.pyplot as plt
import numpy as np
# 構建數據
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
y_data = [58000, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
bar_width = 0.3
# Y軸數據使用range(len(x_data)),也就是0、1、2、……
plt.barh(y=range(len(x_data)),
width=y_data,
label='產品1',
color='steelblue',
alpha=0.8,
height=bar_width)
# Y軸數據使用np.arange(len(x_data)) + bar_width,也就是bar_width、1+bar_width、2+bar_width……
plt.barh(y=np.arange(len(x_data)) + bar_width,
width=y_data2,
label='產品2',
color='indianred',
alpha=0.8,
height=bar_width)
# 在柱狀圖上顯示具體的數值,ha參數控制水平對齊方式,va參數控制垂直對齊方式
for y, x in enumerate(y_data):
plt.text(x + 5000,
y - bar_width / 2,
'%s' % x,
ha='center',
va='bottom')
for y, x in enumerate(y_data2):
plt.text(x + 5000,
y + bar_width / 2,
'%s' % x,
ha='center',
va='bottom')
# 設置Y軸刻度
plt.yticks(np.arange(len(x_data)) + bar_width / 2, x_data)
# 設置標題
plt.title("產品比較")
# 爲兩個座標軸設置名稱
plt.xlabel("銷量")
plt.ylabel("年份")
# 顯示圖例
plt.legend()
plt.show()
運行效果
(四)散點圖
實際上,散點圖和折線圖類似,區別是折線圖會將各個點用線連接起來,而散點圖不會。調用Matplotlib的scatter()函數可以繪製散點圖,該函數接收如下參數:
- x:指定X軸數據。
- y:指定Y軸數據。
- s:指定散點的大小。
- c:指定散點的顏色。
- alpha:指定散點的透明度。
- linewidths:指定散點邊框線的寬度。
- edgecolors:指定散點邊框的顏色。
- marker:指定散點的圖形樣式。
- cmap:指定散點的顏色映射,會使用不同的顏色來區分散點的值。
散點樣式表
樣式字符 | 樣式 |
---|---|
‘.’ | 點標記 |
‘,’ | 像素標記 |
‘o’ | 圓形標記 |
‘v’ | 向下三角形標記 |
‘^’ | 向上三角形標記 |
‘<’ | 向左三角形標記 |
‘>’ | 向右三角形標記 |
‘1’ | 向下三叉標記 |
‘2’ | 向上三叉標記 |
‘3’ | 向左三叉標記 |
‘4’ | 向右三叉標記 |
‘s’ | 正方形標記 |
‘p’ | 五邊形標記 |
‘*’ | 星號標記 |
‘h’ | 八邊形標記 |
‘H’ | 另一種八邊形標記 |
‘+’ | 加號標記 |
‘x’ | x標記 |
‘D’ | 菱形標記 |
‘d’ | 尖菱形標記 |
‘|’ | 豎線標記 |
‘_’ | 橫線標記 |
示例
import matplotlib.pyplot as plt
import numpy as np
plt.figure()
# 定義從-pi到pi之間的數據,平均取64個數據點
x_data = np.linspace(-np.pi, np.pi, 64, endpoint=True)
# 將整個figure分成兩行兩列,第三個參數表示將圖形放在第1個網格中
# 沿着正弦曲線繪製散點圖
plt.scatter(x_data,
np.sin(x_data),
c='purple',
s=50,
alpha=0.5,
marker='p',
linewidths=1,
edgecolors=['green', 'yellow'])
# 繪製第二個散點圖(只包含一個起點),突出起點
plt.scatter(x_data[0], np.sin(x_data)[0], c='red', s=150, alpha=1)
# 繪製第三個散點圖(只包含一個結束點),突出結束點
plt.scatter(x_data[63], np.sin(x_data)[63], c='black', s=150, alpha=1)
plt.gca().spines['right'].set_color('none')
plt.gca().spines['top'].set_color('none')
plt.gca().spines['bottom'].set_position(('data', 0))
plt.gca().spines['left'].set_position(('data', 0))
plt.title('正弦曲線的散點圖')
plt.show()
運行效果:
(五)等高線圖
等高線圖需要三維數據,其中X、Y軸數據決定座標點,還需要對應的高度數據(相當於Z軸)來決定不同座標點的高度。程序調用contour()函數繪製等高線,調用contourf()函數爲等高線圖填充顏色。
contour()、contourf()函數常用參數如下:
- X:指定X軸數據
- Y:指定Y軸數據
- Z:指定X、Y座標對應點的高度數據
- colors:指定不同高度的等高線的顏色
- alpha:指定等高線的透明度
- cmap:指定登高線的顏色映射,即自動使用不同的顏色來區分不同的高度區域
- linewidths:指定等高線的寬度
- linestyles:指定等高線的樣式
示例
import matplotlib.pyplot as plt
import numpy as np
delta = 0.025
# 生成代表x軸數據的列表
x = np.arange(-3.0, 3.0, delta)
# 生成代表y軸數據的列表
y = np.arange(-2.0, 2.0, delta)
# 對X、y數據進行網格化
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
# 計算Z軸數據(高度數據)
Z = (Z1 - Z2) * 2
# 爲等高線圖填充顏色,16指定將等高線分爲幾部分
plt.contourf(x, y, Z, 16, alpha=0.75, cmap='rainbow') # 使用顏色映射來區分不同高度的區域
# 繪製等高線
c = plt.contour(x, y, Z, 16, colors='black', linewidths=0.5)
# 繪製等高線數據
plt.clabel(c, inline=True, fontsize=10)
# 去除座標軸
plt.xticks(())
plt.yticks(())
# 設置標題
plt.title('等高線圖')
# 爲兩個座標軸設置名稱
plt.xlabel("緯度")
plt.ylabel("經度")
plt.show()
運行效果:
以上代碼中要注意一個地方,很多書裏都將c = plt.contour(x, y, Z, 16, colors='black', linewidths=0.5)
中的linewidths寫成了linewidth。
(六)3D圖形
調用Axes3D對象的plot_surface()方法來繪製3D圖形。
示例
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(12, 8))
ax = Axes3D(fig)
delta = 0.125
# 生成代表X軸數據的列表
x = np.arange(-3.0, 3.0, delta)
# 生成代表Y軸數據的列表
y = np.arange(-2.0, 2.0, delta)
# 對x、y數據進行網格化
X, Y = np.meshgrid(x, y)
Z1 = np.exp(-X**2 - Y**2)
Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2)
# 計算Z軸數據(高度數據)
Z = (Z1 - Z2) * 2
# 繪製3D圖形
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=plt.get_cmap('rainbow'))
# 設置Z軸範圍
ax.set_zlim(-2, 2)
# 設置標題
plt.title("3D圖")
plt.show()
運行效果:
三、使用Pygal生成數據圖
Pygal是另一個簡單易用的數據圖庫,它以面向對象的方式來創建各種數據圖,而且使用Pygal可以非常方便地生成各種格式的數據圖,包括PNG 、SVG 等。使用Pygal也可以生成XML etree、HTML 表格(這些都需要安裝其他包)。
(一)安裝Pygal包
pip安裝
pip install pygal
查看文檔
python -m pydoc -p 8899
(二)Pygal數據圖入門
使用Pygal生成數據圖步驟如下:
① 創建Pygal數據圖對象。有pygal.Bar,pygal.Pie,Pygal.Line等對象類型。
② 調用數據圖對象的add()方法添加數據。
③ 調用Config對象的屬性配置數據圖。
④ 調用數據圖對象的render_to_xxx()方法將數據圖渲染到指定的輸出節點——可以是PNG圖片、SVG文件等。
示例
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定義兩個列表分別作爲兩組柱狀圖的Y軸數據
y_data = [5800, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 創建pygal.Bar對象
bar = pygal.Bar()
# 添加兩組代表條柱的數據
bar.add('產品1', y_data)
bar.add('產品2', y_data2)
# 設置X軸的刻度值
bar.x_labels = x_data
bar._title = '產品歷年銷售量'
# 設置X,Y軸的標題
bar._x_title = '年份'
bar._y_title = '銷量'
# 指定將數據圖輸出到SVG文件中
bar.render_to_file('pygal_bar_test.svg')
運行後生成pygal_bar_test.svg文件,用瀏覽器打開效果如下:
(三)配置Pygal數據圖
Pygal模塊下有一個config模塊,該模塊包含了BaseConfig、CommonConfig、Config、SerieConfig等配置類。
部分配置屬性示例
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定義兩個列表分別作爲兩組柱狀圖的Y軸數據
y_data = [5800, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 創建pygal.Bar對象(柱狀圖)
bar = pygal.Bar()
# 添加兩組代表條柱的數據
bar.add('產品1', y_data)
bar.add('產品2', y_data2)
# 設置X軸的刻度值
bar.x_labels = x_data
bar.title = '產品歷年銷量'
# 設置X、Y軸的標題
bar.x_title = '年份'
bar.y_title = '銷量'
# 設置X軸的刻度值旋轉45°
bar.x_label_rotation = 45
# 設置將圖例放在底部
bar.legend_at_bottom = True
# 設置數據圖四周的頁邊距
# 也可通過margin_bottom、margin_left、margin_right、margin_top只設置單獨一邊的頁邊距
bar.margin = 35
# 隱藏Y軸上的網絡線
bar.show_y_guides = False
# 顯示X軸上的網格線
bar.show_x_guides = True
# 指定將數據圖輸出到SVG文件中
bar.render_to_file('pygal_bar_config.svg')
pygal_bar_config.svg文件效果:
四、Pygal支持的常見數據圖
(一)折線圖
使用pygal.Line 類來表示折線圖,程序創建pygal.Line對象就是創建折線圖。
示例
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定義兩個列表分別作爲兩組柱狀圖的Y軸數據
y_data = [5800, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 創建pygal.Line對象(折線圖)
line = pygal.Line()
# 添加兩組代表折線的數據
line.add('產品1', y_data)
line.add('產品2', y_data2)
# 設置X軸的刻度值
line.x_labels = x_data
# 重新設置Y軸的刻度值
line.y_labels = [20000, 40000, 60000, 80000, 100000]
line._title = '產品歷年銷量'
# 設置X,Y軸的標題
line.x_title = '年份'
line.y_title = '銷量'
# 設置將圖例放在底部
line.legend_at_bottom = True
# 指定將數據圖輸出到SVG文件中
line.render_to_file('pygal_line_test.svg')
SVG圖形效果:
(二)水平柱狀圖和水平折線圖
使用pygal.HorizontalBar類來表示水平柱狀圖。使用pygal.HorizontalBar生成水平柱狀圖的步驟與創建普通柱狀圖的步驟基本相同。
示例
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定義兩個列表分別作爲兩組柱狀圖的Y軸數據
y_data = [5800, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 創建pygal.HorizontalBar對象
horizontal_bar = pygal.HorizontalBar()
# 添加兩組數據
horizontal_bar.add('產品1', y_data)
horizontal_bar.add('產品2', y_data2)
# 設置Y軸的刻度值
horizontal_bar.x_labels = x_data
# 重新設置X軸的刻度值
horizontal_bar.y_labels = [20000, 40000, 60000, 80000, 100000]
horizontal_bar._title = '產品歷年銷量'
# 設置X、Y軸的標題
horizontal_bar.x_title = '銷量'
horizontal_bar.y_title = '年份'
# 設置將圖例放在底部
horizontal_bar.legend_at_bottom = True
# 指定將數據圖輸出到SVG文件中
horizontal_bar.render_to_file('pygal_horizontal_bar_test.svg')
SVG效果圖:
與水平柱狀圖類似的還有水平折線圖,水平折線圖使用pygal.HorizontalLine 類來表示,水平折線圖的X 軸刻度值同樣使用y_labels屬性來設置,而Y軸刻度值才使用x_labels屬性來設置。
(三)疊加柱狀圖和疊加折線圖
疊加柱狀圖使用pygal.StackedBar 類來表示,程序使用pygal.StackedBar 創建疊加柱狀圖的步驟與創建普通柱狀圖的步驟基本相同。
示例
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定義兩個列表分別作爲兩組柱狀圖的Y軸數據
y_data = [5800, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 創建pygal.StackedBar對象
stacked_bar = pygal.StackedBar()
# 添加兩組數據
stacked_bar.add('產品1', y_data)
stacked_bar.add('產品2', y_data2)
# 設置X軸的刻度值
stacked_bar.x_labels = x_data
# 重新設置Y軸的刻度值
stacked_bar.y_labels = [20000, 40000, 60000, 80000, 100000]
stacked_bar.title = '產品歷年銷量'
# 設置X、Y軸的標題
stacked_bar.y_title = '年份'
stacked_bar.x_title = '銷量'
# 設置將圖例放在底部
stacked_bar.legend_at_bottom = True
# 指定將數據圖輸出到SVG文件中
stacked_bar.render_to_file('pygal_stacked_bar_test.svg')
SVG效果圖:
(四)餅圖
Pygal提供了pygal.Pie 類來支持餅圖,支持如下兩個特有的屬性。
- inner_radius:設置餅圖內圈的半徑。通過設置該屬性可以實現環形數據圖。
- half_pie:將該屬性設置爲True,可以實現半圓的餅圖。
示例
import pygal
# 準備數據
data = [
0.16881, 0.14966, 0.07471, 0.06992, 0.04762, 0.03541, 0.02925, 0.02411,
0.02316, 0.01409, 0.36326
]
# 準備標籤
labels = [
'Java', 'C', 'C++', 'Python', 'Visual Basic.NET', 'c#', 'PHP',
'JavaScript', 'SQL', 'Assembly langugage', '其它'
]
# 創建pygal.Pie對象
pie = pygal.Pie()
# 採用循環爲餅圖添加數據
for i, per in enumerate(data):
pie.add(labels[i], per)
pie.title = '2018年8月編程語言排行'
# 設置將圖例放在底部
pie.legend_at_bottom = True
# 設置內圈的半徑長度
pie.inner_radius = 0.4
# 創建班員數據圖
pie.half_pie = True
# 指定將數據圖輸出到SVG文件中
pie.render_to_file('language_percent.svg')
SVG效果圖:
(五)點圖
點圖使用點( 圓) 的大小來表示數值的大小。Pygal 使用pygal.Dot 類表示點圖,創建點圖的方式與創建柱狀圖的方式基本相同。
示例
import pygal
x_data = ['2011', '2012', '2013', '2014', '2015', '2016', '2017']
# 定義兩個列表分別作爲兩組柱狀圖的Y軸數據
y_data = [5800, 60200, 63000, 71000, 84000, 90500, 107000]
y_data2 = [52000, 54200, 51500, 58300, 56800, 59500, 62700]
# 創建pygal.Dot對象
dot = pygal.Dot()
dot.dots_size = 5
# 添加兩組數據
dot.add('產品1', y_data)
dot.add('產品2', y_data2)
# 設置X軸的刻度值
dot.x_labels = x_data
# 重新設置Y軸的刻度值
dot.y_labels = ['產品1', '產品2']
# 設置Y軸刻度值的旋轉角度
dot.y_label_rotation = 45
dot.title = '產品歷年銷量'
# 設置X軸的標題
dot.x_title = '年份'
# 設置將圖例放在底部
dot.legend_at_bottom = True
# 指定將數據圖輸出的SVG文件中
dot.render_to_file('pygal_dot_test.svg')
SVG效果圖:
(六)儀表(Gauge)圖
儀表圖類似於一個儀表盤,在儀表盤內使用不同的指針代表不同的數據。Pygal使用pygal.Gauge類表示儀表圖。程序在創建pygal.Gauge對象之後,爲pygal.Gauge 對象添加數據的方式與爲pygal.Pie對象添加數據的方式相似。pygal.Gauge對象有一個特別的屬性:range ,該屬性用於指定儀表圖的最小值和最大值。
示例
import pygal
# 準備數據
data = [
0.16881, 0.14966, 0.07471, 0.06992, 0.04762, 0.03541, 0.02925, 0.02411,
0.02316, 0.01409, 0.36326
]
# 準備標籤
labels = [
'Java', 'C', 'C++', 'Python', 'Visual Basic.NET', 'c#', 'PHP',
'JavaScript', 'SQL', 'Assembly langugage', '其它'
]
# 創建pygal.Gauge對象
gauge = pygal.Gauge()
gauge.range = [0, 1]
# 採用循環爲儀表圖添加數據
for i, per in enumerate(data):
gauge.add(labels[i], per)
gauge.title = '2018年8月編程語言'
# 設置將圖例放在底部
gauge.legend_at_bottom = True
# 指定將數據圖輸出到SVG文件中
gauge.render_to_file('pygal_gauge_test.svg')
SVG效果圖:
(七)雷達圖
雷達圖適合用於分析各對象在不同維度的優勢和劣勢,通過雷達圖可對比每個對象在不同維度的得分。
假如我們從下表所示的5個方面(平臺健壯性、語法易用性、社區活躍度、市場份額和未來趨勢)的得分來評價各編程語言的優勢。
平臺健壯性 | 語法易用性 | 社區活躍度 | 市場份額 | 未來趨勢 | |
---|---|---|---|---|---|
Java | 5 | 4.0 | 5 | 5 | 5 |
C | 4.8 | 2.8 | 4.8 | 4.8 | 4.9 |
C++ | 4.5 | 2.9 | 4.6 | 4.0 | 4.9 |
Python | 4.0 | 4.8 | 4.9 | 4.0 | 5 |
C# | 3.0 | 4.2 | 2.3 | 3.5 | 2 |
PHP | 4.8 | 4.3 | 3.9 | 3.0 | 4.5 |
雷達圖示例
import pygal
# 準備數據
data = [[5, 4.0, 5, 5, 5], [4.8, 2.8, 4.8, 4.8, 4.9],
[4.5, 2.9, 4.6, 4.0, 4.9], [4.0, 4.8, 4.9, 4.0, 5],
[3.0, 4.2, 2.3, 3.5, 2], [4.8, 4.3, 3.9, 3.0, 4.5]]
# 準備標籤
labels = ['Java', 'C', 'C++', 'Python', 'C#', 'PHP']
# 創建pygal.Radar對象
rader = pygal.Radar()
# 採用循環爲雷達圖添加數據
for i, per in enumerate(labels):
rader.add(labels[i], data[i])
rader.x_labels = ['平臺健壯性', '語法易用性', '社區活躍度', '市場份額', '未來趨勢']
rader.title = '編程語言對比圖'
# 控制各得分點的大小
rader.dots_size = 8
# 設置將圖例放在底部
rader.legend_at_bottom = True
# 指定將數據圖輸出的SVG文件中
rader.render_to_file('language_compare.svg')
SVG效果圖:
五、處理數據
(一)CSV文件格式
csv文件格式的本質是一種以文本存儲的表格數據(使用Excel工具即可讀寫csv 文件) 。csv文件的每行代表一行數據,每行數據中每個單元格內的數據以逗號隔開。
Python提供了csv模塊來讀寫csv文件。由於csv 文件的格式本身比較簡單( 通常第一行是表頭,用於說明每列數據的含義, 接下來每行代表一行數據) , 因此使用csv模塊讀取csv文件也非常簡單。
① 創建CSV模塊的讀取器
② 循環調用CSV讀取器的next()方法逐行讀取CSV文件內容即可。next()方法返回一個list列表代表一行數據,list列表的每個元素代表一個單元格數據。
CSV數據讀取示例
import csv
filename = 'guangzhou-2017.csv'
# 打開文件
with open(filename) as f:
# 創建CSV讀取器
reader = csv.reader(f)
# 讀取第一行,這行是表頭數據
header_row = next(reader)
print(header_row)
# 讀取第二行,這行是真正的數據
first_row = next(reader)
print(first_row)
使用Matplotlib結合CSV文件讀取展示圖表示例
import csv
from datetime import datetime
from matplotlib import pyplot as plt
filename = 'guangzhou-2017.csv'
# 打開文件
with open(filename) as f:
# 創建CSV讀取器
reader = csv.reader(f)
# 讀取第一行,這行是表頭數據
header_row = next(reader)
print(header_row)
# 定義讀取起始日期
start_date = datetime(2017, 6, 30)
# 定義讀取結束日期
end_date = datetime(2017, 8, 1)
# 定義三個list列表作爲展示的數據
dates, highs, lows = [], [], []
for row in reader:
# 將第一列的值格式化爲日期
d = datetime.strptime(row[0], '%Y-%m-%d')
# 只展示2017年7月的數據
if start_date < d < end_date:
dates.append(d)
highs.append(int(row[1]))
lows.append(int(row[2]))
# 配置圖形
fig = plt.figure(dpi=128, figsize=(12, 9))
# 繪製最高氣溫的折線
plt.plot(dates,
highs,
c='red',
label='最高氣溫',
alpha=0.5,
linewidth=2.0,
linestyle='-',
marker='v')
# 繪製最低氣溫的折線
plt.plot(dates,
lows,
c='blue',
label='最低氣溫',
alpha=0.5,
linewidth=3.0,
linestyle='-.',
marker='o')
# 爲兩個數據的繪圖區填充顏色
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
# 設置標題
plt.title("2017年7月廣州最高氣溫和最低氣溫")
# 爲兩個座標軸設置名稱
plt.xlabel("日期")
# 該方法繪製歇着的日期標籤
fig.autofmt_xdate()
plt.ylabel("氣溫(℃)")
# 顯示圖例
plt.legend()
ax = plt.gca()
# 設置右邊座標軸線的顏色
ax.spines['right'].set_color('none')
# 設置頂部座標軸線的顏色
ax.spines['top'].set_color('none')
plt.show()
運行效果:
使用Pygal結合CSV讀取展示數據圖示例
import csv
import pygal
filename = 'guangzhou-2017.csv'
# 打開文件
with open(filename) as f:
# 創建CSV讀取器
reader = csv.reader(f)
# 讀取第一行數據的表頭信息
header_row = next(reader)
print(header_row)
# 準備展示的數據
shades, sunys, cloudys, rainys = 0, 0, 0, 0
for row in reader:
if '陰' in row[3]:
shades += 1
elif '晴' in row[3]:
sunys += 1
elif '雲' in row[3]:
cloudys += 1
elif '雨' in row[3]:
rainys += 1
else:
print(row[3])
# 創建pygal.pei對象
pie = pygal.Pie()
# 爲餅圖添加數據
pie.add("陰", shades)
pie.add("晴", sunys)
pie.add("多雲", cloudys)
pie.add("雨", rainys)
pie.title = '2017年廣州天氣彙總'
# 設置圖例放在底部
pie.legend_at_bottom = True
# 指定將數據圖輸出到SVG文件中
pie.render_to_file('pygal_guangzhou_weather.svg')
SVG效果:
(二)JSON數據
示例1
import json
from matplotlib import pyplot as plt
import numpy as np
filename = 'gdp_json.json'
# 讀取JSON格式的GDP數據
with open(filename) as f:
gdp_list = json.load(f)
# 使用list列表依次保存中國、美國、日本、俄羅斯、加拿大的GDP值
country_gdps = [{}, {}, {}, {}, {}]
country_codes = ['CHN', 'USA', 'JPN', 'RUS', 'CAN']
# 遍歷列表的每個元素,每個元素都是一個GDP數據項
for gdp_dict in gdp_list:
for i, country_code in enumerate(country_codes):
# 只讀取指定國家的數據
if gdp_dict['Country Code'] == country_code:
year = gdp_dict['Year']
# 值讀取從2001年到2016年的數據
if 2017 > year > 2000:
country_gdps[i][year] = gdp_dict['Value']
country_gdp_list = [[], [], [], [], []]
# 構建時間數據
x_data = range(2001, 2017)
for i in range(len(country_gdp_list)):
for year in x_data:
# 除以1e8,讓數值變成以億爲單位
country_gdp_list[i].append(country_gdps[i][year] / 1e8)
bar_width = 0.15
fig = plt.figure(dpi=128, figsize=(15, 9))
colors = ['indianred', 'steelblue', 'gold', 'lightpink', 'seagreen']
# 定義國家名稱列表
countries = ['中國', '美國', '日本', '俄羅斯', '加拿大']
# 採用循環繪製5組柱狀圖
for i in range(len(colors)):
# 使用自定義的X座標將數據分開
plt.bar(x=np.arange(len(x_data)) + bar_width * i,
height=country_gdp_list[i],
label=countries[i],
color=colors[i],
alpha=0.8,
width=bar_width)
# 僅在中國、美國的條柱上繪製GDP值
if i < 2:
for x, y in enumerate(country_gdp_list[i]):
plt.text(x, y + 100, '%.0f' % y, ha='center', va='bottom')
# 爲X軸設置刻度值
plt.xticks(np.arange(len(x_data)) + bar_width * 2, x_data)
# 設置標題
plt.title("從2001年到2016年各國GDP對比")
# 爲兩個座標軸設置名稱
plt.xlabel("年份")
plt.ylabel("GDP(億美元)")
# 顯示圖例
plt.legend()
plt.show()
運行效果:
(三)數據清洗
當程序使用Python 進行數據展示時,經常發現數據存在以下兩種情況。
- 數據丟失
- 數據格式錯誤
對於數據丟失的情況,程序應i亥生成報告:對於數據格式發生錯誤的情況, 程序應該能略過發生錯誤的數據,繼續處理後面的程序,並報告發生錯誤的數據。
(四)讀取網絡數據
示例 爬取並展示http://lishi.tianqi.com站點的數據
import re
from datetime import datetime
from datetime import timedelta
from matplotlib import pyplot as plt
from urllib.request import *
# 定義一個函數讀取http://lishi.tianqi.com站點的數據
def get_html(city, year, month):
url = 'http://lishi.tianqi.com/' + city + '/' + str(year) + str(
month) + '.html'
# 創建請求
request = Request(url)
# 添加請求頭
request.add_header(
'User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64)' +
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
)
response = urlopen(request)
# 獲取服務器響應
return response.read().decode('utf-8')
# 定義三個list列表作爲展示的數據
dates, highs, lows = [], [], []
city = 'chongqing'
year = '2018'
months = [
'01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'
]
prev_day = datetime(2017, 12, 31)
# 循環讀取每個月的天氣數據
for month in months:
html = get_html(city, year, month)
# 將HTML響應拼接起來
text = "".join(html.split())
# 定義包含天氣信息的div的正則表達式
patten = re.compile(r'<ulclass="lishitable_contentclearfix">(.*?)</ul>')
table = re.findall(patten, text)
patten1 = re.compile(r'<li.*?>(.*?)</li>')
uls = re.findall(patten1, table[0])
# 去除最後一個包含“查看更多”的<li>
uls = uls[:-1]
for ul in uls:
# 定義解析天氣信息的正則表達式
patten2 = re.compile(r'<div.*?>(.*?)</div>')
lis = re.findall(patten2, ul)
print(lis)
# 解析得到日期數據
d_str = re.findall(r'">(.*?)</a>', lis[0])[0]
try:
# 將日期字符串格式化爲日期
cur_day = datetime.strptime(d_str, '%Y-%m-%d')
# 解析得到最高氣溫和最低氣溫
high = int(lis[1])
low = int(lis[2])
except ValueError:
print(cur_day, '數據出現錯誤')
else:
# 計算前、後兩天數據的時間差
diff = cur_day - prev_day
# 如果前、後兩天數據的時間差不是相差一天,則說明數據有問題
if diff != timedelta(days=1):
print('%s之間少了%d天的數據' % (cur_day, diff.days - 1))
dates.append(cur_day)
highs.append(high)
lows.append(low)
prev_day = cur_day
# 配置圖形
fig = plt.figure(dpi=128, figsize=(12, 9))
# 繪製最高氣溫的折線
plt.plot(dates, highs, c='red', label='最高氣溫', alpha=0.5, linewidth=2.0)
# 繪製最低氣溫的折線
plt.plot(dates, lows, c='blue', label='最低氣溫', alpha=0.5, linewidth=2.0)
# 爲兩個數據的繪圖區域填充顏色
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
# 設置標題
plt.title("%s年重慶最高氣溫和最低氣溫" % year)
# 爲兩個座標軸設置名稱
plt.xlabel("日期")
# 該方法繪製斜着的日期標籤
fig.autofmt_xdate()
plt.ylabel("氣溫(℃)")
# 顯示圖例
plt.legend()
ax = plt.gca()
# 設置右邊座標線不顯示
ax.spines['right'].set_color('none')
# 設置頂部座標線不顯示
ax.spines['top'].set_color('none')
plt.show()
運行效果:
練習
1.使用Matplotlib生成折線圖,分析自己在兩個月內體重變化與運動時間之間的關係。
import matplotlib.pyplot as plt
# 定義兩個列表分別作爲X軸、Y軸數據
# Y軸代表運動時間,X軸代表體重
y_data = [
'60分鐘', '30分鐘', '45分鐘', '60分鐘', '30分鐘', '45分鐘', '60分鐘', '30分鐘', '45分鐘',
'60分鐘', '30分鐘', '45分鐘', '60分鐘', '30分鐘', '45分鐘', '60分鐘', '30分鐘', '45分鐘',
'60分鐘', '30分鐘', '45分鐘', '60分鐘', '30分鐘', '45分鐘', '60分鐘', '30分鐘', '45分鐘',
'60分鐘', '30分鐘', '45分鐘'
]
x_data = [
68, 67.5, 67, 66, 66.5, 66, 65.5, 65, 64.5, 64, 64.5, 64, 63.5, 63, 64, 63,
62.5, 62, 61.5, 61, 61.5, 60, 59.5, 59, 58.5, 58, 57.5, 57, 56.5, 56
]
# 第一個列表代表橫座標的值,第二個列表代表縱座標的值
plt.plot(x_data, y_data)
# 調用show()函數顯示圖形
plt.show()
2.使用Pygal生成餅圖,分析本年度自己在生活、教育學習、健身、旅遊、娛樂各方面的時間投入和金錢投入。
import pygal
# 準備數據
data = [191400, 50000, 1000, 30000, 110000]
data1 = [365, 100, 125, 30, 200]
# 準備標籤
labels = ['生活', '教育學習', '健身', '旅遊', '娛樂']
# 創建pygal.Pie對象
pie = pygal.Pie()
# 採用循環爲餅圖添加數據
for i, per in enumerate(data):
pie.add(labels[i], per)
pie.title = '2019年消費投入圖'
# 設置將圖例放在底部
pie.legend_at_bottom = True
# 設置內圈的半徑長度
pie.inner_radius = 0.4
# 指定將數據圖輸出到SVG文件中
pie.render_to_file('my.svg')
# 創建pygal.Pie對象
pie1 = pygal.Pie()
# 採用循環爲餅圖添加數據
for i, per in enumerate(data1):
pie1.add(labels[i], per)
pie1.title = '2019年時間投入圖'
# 設置將圖例放在底部
pie1.legend_at_bottom = True
# 設置內圈的半徑長度
pie1.inner_radius = 0.5
# 指定將數據圖輸出到SVG文件中
pie.render_to_file('my1.svg')
3.使用隨機數生成5000 個(-3, -3 )~(3,3 )範圍的點,並使用散點圖繪製它們。
import matplotlib.pyplot as plt
import random
plt.figure()
x_data, y_data = [], []
for i in range(5000):
x_data.append(random.uniform(-3, 3))
for i in range(5000):
y_data.append(random.uniform(-3, 3))
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.scatter(x_data,
y_data,
c='purple',
s=50,
alpha=0.5,
marker='p',
linewidths=1,
edgecolors=['green', 'yellow'])
# 繪製第二個散點圖(只包含一個起點),突出起點
plt.scatter(x_data[0], y_data[0], c='red', s=150, alpha=1)
# 繪製第三個散點圖(只包含一個結束點),突出結束點
plt.scatter(x_data[4999], y_data[4999], c='black', s=150, alpha=1)
plt.gca().spines['right'].set_color('none')
plt.gca().spines['top'].set_color('none')
plt.gca().spines['bottom'].set_position(('data', 0))
plt.gca().spines['left'].set_position(('data', 0))
plt.title('隨機數的散點圖')
plt.show()
4.從https://www.tiobe.com/tiobe-index/網站查找2018年各月Python和Java兩門語言的市場份額,並繪製它們的柱狀圖進行對比。
import csv, pygal
filename = 'exercise\language.csv'
x_data = ['0' + str(i + 1) for i in range(12)]
java_data = [0] * 12
python_data = [0] * 12
# 打開文件
with open(filename) as f:
reader = csv.reader(f)
header_row = next(reader)
for row in reader:
# Java的數據
if row[0] == 'java':
java_data[int(row[2][5:]) - 1] = float(row[1])
# Python的數據
elif row[0] == 'python':
python_data[int(row[2][5:]) - 1] = float(row[1])
bar = pygal.Bar()
bar.add('Java', java_data)
bar.add('python', python_data)
bar.x_labels = x_data
bar.title = '2018年各月Java與Python市場份額對比圖'
bar.x_title = '月份'
bar.y_title = '份額'
bar.legend_at_bottom = True
bar.render_to_file('language.svg')
5.從https://datahub.io網站下載世界各國的人口數據,並繪製中國、印度歷年人口變化的折線圖。
import json
import pygal
pop_filename = 'exercise\\population-figures-by-country.json'
# 讀取JSON格式的人口數據
with open(pop_filename) as f:
pop_list = json.load(f)
# 構建時間數據
x_data = range(1970, 2017)
# 使用list列表依次保存中國、印度的人口
country_pops_list = [[], []]
for pop_dict in pop_list:
# 獲取中國的人口數據
if pop_dict['Country_Code'] == 'CHN':
for year in x_data:
country_pops_list[0].append(pop_dict['Population_in_%d' % year] /
10000)
# 獲取印度的人口數據
if pop_dict['Country_Code'] == 'IND':
for year in x_data:
country_pops_list[1].append(pop_dict['Population_in_%d' % year] /
10000)
# 定義國家名稱列表
countries = ['中國', '印度']
# 創建pygal.Bar對象
bar = pygal.Bar()
# 採用循環添加代表條柱的數據
for i in range(len(countries)):
bar.add(countries[i], country_pops_list[i])
bar.width = 1100
# 設置X軸的刻度值
bar.x_labels = x_data
bar.title = '1970-2016年中國印度人口對比'
bar.x_title = '年份'
bar.y_title = '人口(萬)'
# 設置X軸的刻度值旋轉45度
bar.x_label_rotation = 45
# 設置將圖例放在底部
bar.legend_at_bottom = True
# 將數據圖輸出到文件
bar.render_to_file('population.svg')
6.從http://lishi.tianqi.com網站讀取深圳的2017年曆史天氣數據,並繪製最高氣溫、最低氣溫的折線圖。
import re
from datetime import datetime
from datetime import timedelta
from matplotlib import pyplot as plt
from urllib.request import *
# 定義一個函數讀取http://lishi.tianqi.com站點的數據
def get_html(city, year, month):
url = 'http://lishi.tianqi.com/' + city + '/' + str(year) + str(
month) + '.html'
# 創建請求
request = Request(url)
# 添加請求頭
request.add_header(
'User-Agent', 'Mozilla/5.0 (Windows NT 10.0; WOW64)' +
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36'
)
response = urlopen(request)
# 獲取服務器響應
return response.read().decode('utf-8')
# 定義三個list列表作爲展示的數據
dates, highs, lows = [], [], []
city = 'shenzhen'
year = '2017'
months = [
'01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'
]
prev_day = datetime(2016, 12, 31)
# 循環讀取每個月的天氣數據
for month in months:
html = get_html(city, year, month)
# 將HTML響應拼接起來
text = "".join(html.split())
# 定義包含天氣信息的div的正則表達式
patten = re.compile(r'<ulclass="lishitable_contentclearfix">(.*?)</ul>')
table = re.findall(patten, text)
patten1 = re.compile(r'<li.*?>(.*?)</li>')
uls = re.findall(patten1, table[0])
# 去除最後一個包含“查看更多”的<li>
uls = uls[:-1]
for ul in uls:
# 定義解析天氣信息的正則表達式
patten2 = re.compile(r'<div.*?>(.*?)</div>')
lis = re.findall(patten2, ul)
print(lis)
# 解析得到日期數據
d_str = re.findall(r'">(.*?)</a>', lis[0])[0]
try:
# 將日期字符串格式化爲日期
cur_day = datetime.strptime(d_str, '%Y-%m-%d')
# 解析得到最高氣溫和最低氣溫
high = int(lis[1])
low = int(lis[2])
except ValueError:
print(cur_day, '數據出現錯誤')
else:
# 計算前、後兩天數據的時間差
diff = cur_day - prev_day
# 如果前、後兩天數據的時間差不是相差一天,則說明數據有問題
if diff != timedelta(days=1):
print('%s之間少了%d天的數據' % (cur_day, diff.days - 1))
dates.append(cur_day)
highs.append(high)
lows.append(low)
prev_day = cur_day
# 配置圖形
fig = plt.figure(dpi=128, figsize=(12, 9))
# 繪製最高氣溫的折線
plt.plot(dates, highs, c='red', label='最高氣溫', alpha=0.5, linewidth=2.0)
# 繪製最低氣溫的折線
plt.plot(dates, lows, c='blue', label='最低氣溫', alpha=0.5, linewidth=2.0)
# 爲兩個數據的繪圖區域填充顏色
plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)
# 設置標題
plt.title("%s年重慶最高氣溫和最低氣溫" % year)
# 爲兩個座標軸設置名稱
plt.xlabel("日期")
# 該方法繪製斜着的日期標籤
fig.autofmt_xdate()
plt.ylabel("氣溫(℃)")
# 顯示圖例
plt.legend()
ax = plt.gca()
# 設置右邊座標線不顯示
ax.spines['right'].set_color('none')
# 設置頂部座標線不顯示
ax.spines['top'].set_color('none')
plt.show()