本文完整程式碼及資料已上傳至我的
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
倉庫中找到對應資料和程式碼~
以上就是本文的全部內容,歡迎在評論區與我進行討論~