在模仿中精進數(shù)據(jù)可視化02:溫室氣體排放來源可視化

點擊上方"藍字"關(guān)注我們
記錄? ?分享? ?成長
?本文完整代碼已上傳至我的
?Github倉庫https://github.com/CNFeffery/FefferyViz
1 簡介
交通是產(chǎn)生溫室氣體排放的主要來源之一,而本期作為*(在模仿中精進數(shù)據(jù)可視化)*系列的第二期,將帶大家以純Python的方式對加拿大米西索加城市溫室氣體排放研究報告中的如圖1所示的可視化作品進行復(fù)刻,它對溫室氣體排放來源中,交通方面的各排放源排放比例進行可視化:

2.1 觀察原作品
其實原作品整體構(gòu)圖上比較直觀,主要由兩部分組成:
「1 左側(cè)柱狀圖部分」
左側(cè)的柱狀圖無需多言,就是一個簡單的堆疊柱狀圖,利用matplotlib構(gòu)建起來非常方便。
「2 右側(cè)類?;鶊D部分」
到了右側(cè),也是這張圖中最有設(shè)計感的部分,它用類似?;鶊D的方式,將左圖中交通下屬的分類溫室氣體排放比例構(gòu)成進行可視化,這也是本文的重點部分,我們可以利用matplotlib加上一點點簡單的數(shù)學(xué)知識來復(fù)刻它。
2.2 開始動手!
在洞悉了原作品的主要視覺元素之后,接下來我們開始動手復(fù)刻它。
2.2.1 左側(cè)柱狀圖部分
對于左側(cè)的堆疊柱狀圖,其本質(zhì)其實是兩個堆疊起來的矩形,因此我們可以使用matplotlib.patches下的Rectangle來創(chuàng)建矩形。
其使用方法非常簡單,只需要指定矩形「左下角坐標(biāo)」,再填寫矩形對應(yīng)的「寬」與「高」即可自由創(chuàng)建矩形:

我們參考原作品的背景色,以及左側(cè)矩形對應(yīng)y軸的真實數(shù)值,先把左側(cè)的「堆疊柱狀圖」和「圖床背景色」做好:
import?matplotlib.pyplot?as?plt
from?matplotlib.patches?import?Rectangle
#?創(chuàng)建圖床
fig,?ax?=?plt.subplots(figsize=(11,?6))
#?創(chuàng)建buildings對應(yīng)矩形
ax.add_patch(Rectangle((0,?0),?3e6,?3e6,?facecolor='#f38530'))
#?創(chuàng)建transportation對應(yīng)矩形
ax.add_patch(Rectangle((0,?3e6),?3e6,?2.1e6,?facecolor='#4abad0'))
#?設(shè)置x軸范圍
ax.set_xlim(-3e6,?1.7e7)
#?設(shè)置y軸范圍
ax.set_ylim(-4e6,?9e6)
#?設(shè)置背景色
fig.patch.set_facecolor('#efefea')
ax.set_facecolor('#efefea')
#?關(guān)閉坐標(biāo)軸
ax.axis('off');

接著我們在上面代碼的基礎(chǔ)上添加下列代碼,順便把原作品中連接左右側(cè)的3條灰色線條添加上去:
#?添加連接線
ax.plot([3e6,?6e6],?[3e6,?3e6-1.5e6],?color='grey',?linewidth=0.75)
ax.plot([3e6,?6e6],?[5.1e6,?5.1e6+1.5e6],?color='grey',?linewidth=0.75)
ax.plot([6e6,?6e6],?[3e6-1.5e6,?5.1e6+1.5e6],?color='lightgrey',?linewidth=1.5)

這樣,我們就把最簡單的左半邊主要視覺元素組織好了。
2.2.2 右側(cè)類?;鶊D部分
到了本文的核心內(nèi)容——構(gòu)造右側(cè)類?;鶊D部分,為了便于之后的幾何元素制作,我們先把原作品中右側(cè)涉及的數(shù)據(jù)構(gòu)造到數(shù)據(jù)框中:
import?pandas?as?pd
data?=?pd.DataFrame({
????'類型':?['Car',?'Freight',?'Street?Lights',?'GO?Train',?'BRT',?'Bus',?'Taxi',?'Motorcycle'],
????'份額':?[0.8628,?0.0933,?0.0005,?0.001,?0.0121,?0.0133,?0.0165,?0.0005]
})
data['份額累加']?=?data['份額'].cumsum()
data.head()

其中份額累加列的添加是為了方便之后組合幾何元素。
首先我們來繪制右側(cè)最上方的「Car」對應(yīng)的矩形,因為這部分只是簡單的矩形,在上一步的繪圖代碼中添加下列代碼來更新圖像:
height?=?5.1e6?+?1.5e6?-?(3e6?-?1.5e6)
#?右側(cè)圖形
#?最上方矩形
ax.add_patch(Rectangle((6e6,?3e6-1.5e6+0.1372*height),
???????????????????????0.8e7,
???????????????????????0.8628*height,
???????????????????????facecolor='#4ebcd1'))

接下來我們來創(chuàng)建類?;鶊D部分,思路其實很簡單,因為這部分內(nèi)容與「Sigmoid」型函數(shù)對應(yīng)的曲線是很接近的,譬如正弦函數(shù)在到之間的曲線:

根據(jù)這個特點,我們可以結(jié)合第1期中玩過的「老把戲」——線性變換,來輔助生成?;鶙l帶。
我們從最上方矩形的下端開始,利用data中的份額與份額累加,以及到之間的標(biāo)準(zhǔn)正弦函數(shù)曲線,配合線性變換,來構(gòu)造每個類別對應(yīng)條帶的上下邊界,再配合matplotlib中的fill_between來完成條帶的繪制。
首先我們來生成基礎(chǔ)正弦函數(shù)采樣點數(shù)據(jù),以及線性變換函數(shù):
x,?y?=?np.arange(0.5*np.pi,?1.5*np.pi,?0.001),?np.sin(np.arange(0.5*np.pi,?1.5*np.pi,?0.001))
def?scale(xlim,?ylim):
????
????return?(xlim[0]?+?(xlim[1]?-?xlim[0])?*?(x?-?x.min())?/?(x.max()?-?x.min()),
????????????ylim[0]?+?(ylim[1]?-?ylim[0])?*?(y?-?y.min())?/?(y.max()?-?y.min()))
這樣我們就可以在給定x范圍,以及給定y范圍的基礎(chǔ)上,將標(biāo)準(zhǔn)的正弦函數(shù)曲線不同程度的**“壓扁”**,就像下面的例子一樣:
import?numpy?as?np
x,?y?=?np.arange(0.5*np.pi,?1.5*np.pi,?0.001),?np.sin(np.arange(0.5*np.pi,?1.5*np.pi,?0.001))
def?scale(xlim,?ylim):
????
????return?(xlim[0]?+?(xlim[1]?-?xlim[0])?*?(x?-?x.min())?/?(x.max()?-?x.min()),
????????????ylim[0]?+?(ylim[1]?-?ylim[0])?*?(y?-?y.min())?/?(y.max()?-?y.min()))
plt.plot(*scale((0,?1),?(0,?1)))
plt.plot(*scale((0,?1),?(0.25,?1)))
plt.plot(*scale((0,?1),?(0.5,?1)))
plt.plot(*scale((0,?1),?(0.75,?1)));

按照這個思想,我們結(jié)合份額與份額累加值,以兩種色彩交錯的方式構(gòu)造條帶:
#?生成每個條帶的上下底
bands?=?[(scale(xlim=(6e6,?6e6+0.8e7),?
????????????????ylim=(5.1e6+1.5e6-data.at[i,?'份額累加']*height-(i+1)*7e8,
??????????????????????5.1e6+1.5e6-data.at[i,?'份額累加']*height)),?
??????????scale(xlim=(6e6,?6e6+0.8e7),
????????????????ylim=(5.1e6+1.5e6-data.at[i,?'份額累加']*height-data.at[i+1,?'份額']*height-(i+1)*7e8,
??????????????????????5.1e6+1.5e6-data.at[i,?'份額累加']*height-data.at[i+1,?'份額']*height)))
?????????for?i?in?range(data.shape[0]-1)]
colors?=?['#1b7d98',?'#a5dce7']
for?i,?band?in?enumerate(bands):
????if?i?%?2?==?0:
????????ax.fill_between(band[0][0],?band[0][1],?band[1][1],?color='#1b7d98')
????else:
????????ax.fill_between(band[0][0],?band[0][1],?band[1][1],?color='#a5dce7')

這樣子,我們就完成了原作品的主要視覺元素的復(fù)刻。
2.2.3 其他元素的補充
接下來的內(nèi)容就比較簡單,我們只需要把各種文字標(biāo)注、分割線、刻度等小細節(jié)補上即可:
#?其它元素的補充
#?y軸數(shù)值標(biāo)簽
for?y_,?text?in?zip([0,?2e6,?4e6,?6e6],?['0',?'2M',?'4M',?'6M']):
????ax.text(-1e6,?y_,?text,?ha='right',?color='grey',?fontsize=8)
#?添加左側(cè)矩形內(nèi)部標(biāo)注
ax.text(1.5e6,?1.5e6,?'Buildings?3M',?color='white',?
????????ha='center',?fontsize=7,?fontweight='bold')
ax.text(1.5e6,?3e6+1.05e6,?'Transportation?2.1M',?
????????color='white',?ha='center',?fontsize=7,?fontweight='heavy')
#?添加黑色Today標(biāo)注
ax.text(1.5e6,?-5e5,?'Today',?
????????color='black',?ha='center',?
????????fontsize=10,?family='Times?New?Roman')
#?添加右側(cè)文字標(biāo)注
ax.text(1.42e7,?4.5e6,?'Car?86.28%',?fontsize=8,?family='Times?New?Roman')
for?i?in?range(data.shape[0]-1):
????ax.text(1.42e7,?5.1e6+1.5e6-data.at[i,?'份額累加']*height-data.at[i+1,?'份額']*0.5*height-(i+1)*7e5,
????????????'{}?{}%'.format(data.at[i+1,?'類型'],?round(data.at[i+1,?'份額']*100,?2)),
????????????va='center',?fontsize=8,?family='Times?New?Roman')
#?添加y軸標(biāo)題
ax.text(-2.2e6,?3.3e6,?'Annual?Metric?Tons?of?$CO_{2}$eq?Emissions',?
????????rotation=90,?va='center',?fontsize=7.8)
#?上部分隔線
ax.plot([-2.3e6,?1.65e7],?[9e6,?9e6],?color='#327997',?linewidth=0.7)
#?上部黑色說明文字
ax.text(-2.3e6,?
????????7.9e6,?
????????"40%?of?Mississauga's?GHG?emissions?come?from?the?transportation?sector?including?freight.?Less?than?3%?of?these?emissions?currently?come?from?\npublic?transit.",
????????fontsize=7.9,
????????style='italic')
#?上部標(biāo)題
ax.text(-2.3e6,?9.2e6,?'GHG?Emissions?-?Transportation',?
????????color='#327997',?fontweight='heavy')
經(jīng)過這一番操作,最終的結(jié)果如圖10所示:

而原作品中右側(cè)并沒有按照比例的降序排列,如果你想降序排列,只需要在創(chuàng)建data之后對數(shù)據(jù)框按照份額降序并重置index即可~,降序排列后再繪制的效果如圖11所示:

是不是舒服自然了很多了呢~
以上就是本文的全部內(nèi)容,歡迎在評論區(qū)與我進行討論~

加入我們的知識星球【Python大數(shù)據(jù)分析】
愛上數(shù)據(jù)分析!
用了這個jupyter插件,我已經(jīng)半個月沒打開過excel了
Python大數(shù)據(jù)分析
data creates?value
掃碼關(guān)注我們

