瘋狂Python講義學習筆記(含習題)之數據可視化


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()

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章