本文完整代碼及數據已上傳至我的
Github倉庫https://github.com/CNFeffery/FefferyViz
1 簡介
在星球研究所最近的《10萬座大壩的誕生!》一文中,作者們利用豐富的數據可視化手段對我國及世界大型水壩工程的發展分布情況進行了分析展示,而我尤其喜愛其中的一幅作品:
這是一幅信息量豐富且難度較大的數據可視化作品,因為它混合了地理信息可視化與象形柱狀圖,使得繪制它需要多方面的數據可視化知識。
復刻有挑戰性的數據可視化作品正是我這個系列文章的主旨,在今天的文章中,我就將基於Python,教大家如何還原出這幅作品中的主要視覺元素。
2 復刻過程
首先,按照我們這個系列文章的傳統,先來對原作品中的視覺元素進行剖析,進而構思出“逐一攻破”的方法:
2.1 拆解主要視覺元素
- 半球部分
這幅作品首先映入眼簾的自然是其上方對稱布局的兩個半球圖像,要繪制它們其實比較簡單,我們可以利用地球正射投影(Orthographic projection),分別選定不同的中央經緯度,便可得到左右不同視角下的半球。
- 象形柱狀圖部分
原作品中下方部分的象形柱狀圖也是非常的形象生動切合主題,通過觀察可以發現每個大壩logo代表數值200,而末尾不足200的部分就按照余數/200的透明度進行渲染,配合右下角的圖例,幫助讀者快速解讀出信息,這實現起來也不難,我將會使用matplotlib的相關API配合循環語句來實現logo圖片的嵌入。
- 其余輔助視覺元素
除了上面介紹的兩部分視覺主體之外,其余的部分都主要是些文字或符號之類的小部件,模仿起來比較簡單(上方地圖的國家名稱標注部分用代碼自動化的方式反而更費事,因此本文模仿過程略去這部分),可以明顯看出的是其主要的標題等文字內容主要使用了思源宋體。
摸清楚要做的內容之后,下面讓我們開始吧!
2.2 半球部分的制作
正射投影部分,我選擇使用cartopy.ccrs內置的Orthographic(),通過傳入中央經緯度,即可得到期望的半球面:
我們利用mpl_toolkits.axes_grid1.inset_locator中的inset_axes()將兩個半球各自對應的axe對象插入到主體axe中,再利用cartopy的add_geometries進行矢量元素的疊加和色彩映射即可,我已經在數據中算好了歸一化數值方便色彩映射,以左半球為例:
fig, ax = plt.subplots(figsize=(5.4, 8.1))
# 構建左半球圖像
map_left = inset_axes(ax, width='100%', height='100%',
bbox_to_anchor=(0.19, 0.58, 0.26, 0.26),
bbox_transform=ax.transAxes,
axes_class=cartopy.mpl.geoaxes.GeoAxes,
axes_kwargs=dict(map_projection=crs_left))
# 添加陸地面並設置顏色
map_left.add_feature(cfeature.NaturalEarthFeature('physical', 'land', '110m',
edgecolor='none',
facecolor='#d9d9d9'))
# 為不同國家添加面要素並按照歸一化數值上色
for country in ["美國", "墨西哥", "巴西"]:
map_left.add_geometries(data.query('國家 == @country').geometry,
crs=ccrs.PlateCarree(),
facecolor=custom_cmap(data.query('國家==@country').iat[0, -2]),
zorder=999)
# 設置畫框樣式
map_left.spines['geo'].set_linewidth(0.6)
map_left.spines['geo'].set_color('#d9d9d9')
這樣我們就完成了兩個半球部分的制作,順便配合matplotlib中的text()、參數fontproperties以及matplotlib.font_manager來基於思源宋體添加標題:
2.3 象形柱狀圖部分的制作
介紹完半球地圖部分,我們接着來制作象形柱狀圖部分,這部分的核心內容是使用matplotlib.offsetbox下的OffsetImage()、AnnotationBbox(),配合matplotlib自帶的add_artist(),向現有的圖床中插入外部圖片(這里的logo圖片是我通過軟件手繪的~)。
其中OffsetImage()傳入圖片數組變量、縮放比例以及透明度;AnnotationBbox()用於調整所插入圖片在圖中的位置,遵守一行10個logo的最大布局數量,略微構思一下嵌套循環過程,微調位置參數,即可在前面的基礎上,得到下面的圖像:
而右下角圖例中的第一個logo上下漸變的效果其實是配合numpy數組,從上往下線性地降低rgba第四個通道的透明度值得到了,非常的容易~
而圖中其他的小元素譬如各種文字就不贅述了,無非是text()復制粘貼改改參數而已,對完整過程感興趣的朋友可以在文章開頭的Github倉庫中找到對應數據和代碼~
以上就是本文的全部內容,歡迎在評論區與我進行討論~
