如何用R語言繪製並填充相對正確的世界地圖

近幾年來,隨著負笈海外特別是美國的政治學博士陸續學成回國,R逐漸在高校從事政治學量化研究的師生群體中流行起來,形成了與Stata並駕齊驅的局面。與需要付費購買才能使用的商業統計軟體Stata不同,R可以終身免費使用。不僅如此,作為開源、共享、共建的社群,R具備非常強大的功能,在各項運算上都不遜於Stata,在視覺化方面則更勝一籌。具體來說,R中各種各樣的包(package)為我們處理包括地理資訊(Geographic Information)資料在內的各種資料的視覺化提供了便利。換言之,即便我們在沒有或者不會ArcGIS/QGIS等專業地理資訊處理軟體的情況下,只要我們稍微學習一下R,拿到相關的檔案,就能順利地處理這些地理資訊資料。由於筆者最近一直在接觸地理資訊視覺化的相關知識,對這一領域逐漸起了興趣,心想在閱讀實操的時候不如做一做筆記總結經驗。因此,今天的推送與以往的文獻編譯、方法論衡、學人小傳及新刊快遞等欄目有所不同,它是一篇為了方便作者向國內期刊投稿而介紹的實用技術小文。在這篇小文章裡,我們將同讀者朋友分享如何用R繪製並填充相對正確的世界地圖。

目前網上已經有大量現成的教授大家如何用R繪製各種型別地圖的教程,小到繪製一個街區地圖,大到繪製全世界的地圖教程應有盡有。但本文強調的是“相對正確的世界地圖”。看到這裡,讀者朋友可能會好奇我們為什麼還要在“正確”二字前加上“相對”的字樣,是多此一舉還是故弄玄虛,其實都不然。這是因為即便用R繪製並輸出比較正確的地圖也需要結合相關軟體進行進一步的修改。

眾所周知,地圖是一國國家主權和領土的象徵,使用完整正確的地圖也是國內科研工作者應盡的責任與義務,因此我們在對待地圖繪製時應當十分審慎。令人欣慰的是,近年來,不少技術貼的作者在談及如何繪製中國地圖時,都格外強調使用正確、完整的中國地圖的重要性,其在帖中繪製的中國地圖也基本正確。之所以說這些製圖是“基本正確”是因為按照現行地圖出版的標準,用R直接繪製並輸出的地圖與透過自然資源部審查正式出版的地圖還有一些細微的區別。如下圖所示,儘管中國與塔吉克已經正式完成了劃界工作,但由於現行出版的紙質或電子地圖均未做改動,因此該交界處(帕米爾高原東部傾斜坡)仍應使用未定國界線表示:

如何用R語言繪製並填充相對正確的世界地圖

中國和塔吉克之間的未定國界線

當然這不是特別嚴重的問題,在用R輸出高DPI(每英寸點數)的中國地圖圖片後,可以請美工編輯或排版編輯利用Adobe Illustrator、Photoshop等專業製圖軟體將其修改成虛線即可。

但是在不少介紹繪製世界地圖的帖子中,我們會發現其中使用的地圖存在大量的錯誤。持允而論,出現這些錯誤並不能被歸咎到撰寫相關技術貼的作者,他們本身是出於好心與大家分享技術經驗。但由於他們使用的R包或者shape檔案通常都是國外作者開發並且在國際上通行的包,因此難免會出現與國內出版規定不相符合甚至錯誤的情形。舉例來說:這些包或者shp檔案中多以0°經線(本初子午線)為地圖中心,不符合國內出版的關於世界地圖的規定,如果進行投影變換也可能導致出現錯誤(如在繪製地圖上出現冗餘線條和色塊,這並非是投影變換不對所致,而是原作者在製作shape檔案中已經鎖定了投影)。當然這些問題倒不是最嚴重的,最嚴重的錯誤是在國家邊界劃分上的錯誤。其中R中常用的包和世界地圖檔案中關於中國地圖部分的最嚴重錯誤是違背國際社會普遍承認的“一箇中國”原則、將中國大陸和中國臺灣地區分別作為地位相同的不同“政治實體”對待。其次,這些地圖包普遍按照非法的“麥克馬洪線”將中國藏南地區劃入印度,有些還按照非法的“約翰遜線”將中國阿克賽欽劃入印度以及缺乏南海諸島等等。此外,在這些地圖包中,關於印度和巴基斯坦之間的爭議地區——克什米爾地區以及埃及和蘇丹間的爭議地區等地也未按照正確的形式進行繪製。這些錯誤使得作者繪製出的地圖在投稿時極有可能達不到自然資源部稽核透過的標準,最後導致精彩的視覺化部分被刪除,甚為可惜。

為了進一步說明,我們以R中常用的地圖包maps為例,用紅色圓圈標識出一些常見的錯誤劃界,它們分別是:在圖A中,紅圈1處表示地圖按照非法的“麥克馬洪線”將中國藏南地區劃入印度;在圖B中,紅圈2處指地圖未以未定國界線標識中國與塔吉克之間的邊界;紅圈3處表示地圖未標識出印度和巴基斯坦之間的爭議地區——克什米爾地區;而在圖C中,紅圈4表示地圖未標識出埃及與蘇丹之間的爭議地區——哈拉伊卜三角區。

如何用R語言繪製並填充相對正確的世界地圖

錯誤示例

這些錯誤只是其中的一些代表性錯誤,此外還有別的錯誤。由於此類地圖在繪製輸出後需要修改的地方很多,程式十分繁瑣,非常不適合向國內的期刊雜誌投稿。為了方便大家在今後的日常科研學習過程中使用,我們花了好幾天時間搜遍了各大網站,甚至還付費購買了CSDN的一個月會員,終於找到了一個相對適合的shape檔案。與前述的種種shape檔案相比,我們找到的這一shape檔案相對而言需要修改的地方要少很多(缺少的南海諸島和九段線,需要單獨加上,這可以利用ggplot製圖層層疊加的原理進行補全),而且基本符合作者向國內期刊投稿時使用東經150°經線為中心的製圖要求,但美中不足的是缺乏南極洲。

既然找到了shape檔案,那麼我們該怎麼來處理它呢?事實上,shape檔案在本質上就是儲存地理空間資訊的多邊形,我們可以在R中安裝並載入可以讀取多邊形的sf包,這樣我們可以很容易看到shape檔案中儲存的資料結構和形式。本文使用的世界地圖shape檔案的結構並不複雜,它由name, childNum以及geometry三類變數分別儲存對應的資訊。其中name和geometry兩個欄位特別重要,因為如果我們想要在世界地圖上實現相關資料的視覺化,使用的資料中的國家名稱欄位一定要和本地圖中的name相匹配,這需要大家在使用時仔細校對,而geometry欄位中則儲存了多邊形的資訊,反映在地圖中就是各個國家的形狀。

接下來我們以世界銀行釋出的世界治理指數(Worldwide Governance Index)為例,在校對各個國家名的基礎上,繪製世界地圖並按照Regulatory Quality(各國制定與執行促進私營部門發展能力)的指標進行顏色填充。在此,我們略去了設定工作路徑的步驟,讀者朋友可以根據平時的工作習慣自行設定,載入並讀取資料的程式碼如下所示:

library(tidyverse)library(sf)library(readxl)# 讀取以東經150度經線為中心的世界地圖shapeWorldMap <- st_read(“worldmap”)# 讀取南海諸島shapeSCSislands <- st_read(“SCSislands”)# 讀取九段線shapeNineDashLine <- st_read(“NineDashLine”)# 讀取世界銀行釋出的各國制定與執行促進私營部門發展能力的評估資料庫WGIdata <- read_excel(“ex。xlsx”, col_types = c(“text”, “numeric”))# 將上述資料與世界地圖資料按照相同的“name”欄位合併worlddata <- left_join(WorldMap, WGIdata, by = “name”)

看到這裡,有些讀者可能會疑惑,既然我們已經載入了集ggplot2和readr等包為一體的tidyverse包,那麼為什麼我們不將世行的資料儲存成體積更小、讀取更快的csv格式檔案呢?事實上,正如下圖所示,由於該版本地圖shape資料中name欄位中一些國家的名字採用的是非英文,在對照國家名時如果用csv格式儲存世行資料可能會導致特殊字元遺失,從而導致R中資料框中的國家名匹配不上,進而在繪製出來的地圖上可能顯示不少處深灰色,這意味著缺失相關資料。

如何用R語言繪製並填充相對正確的世界地圖

繪製地圖部分的程式碼如下:

# 繪製世界地圖ggplot() + geom_sf(data = worlddata, aes(fill = estimate), colour = “#525252”,size=0。3)+ #繪製世界地圖並按照estimate欄位中的資料上色 geom_sf(data = SCSislands, colour = “#525252”)+ #繪製南海諸島 geom_sf(data = NineDashLine, color = “#525252”, size=0。3)+ #繪製九段線 coord_sf() + #設定投影方式,本處為預設投影 scale_fill_gradient(low=“#deebf7”, high=“#4292c6”)+ #設定藍色的顏色漸變 guides(fill = guide_legend(title=“評估指數”))+ #修改圖例標籤,如在Mac中可能需要設定字型 ggtitle(“2018年世界各國制定與執行促進私營部門發展能力的評估”)+ #給圖片命名,同樣在Mac中可能需要設定字型 theme(panel。grid = element_blank(), panel。background = element_rect(fill = “Aliceblue”), #將背景填充為Aliceblue色模仿大海 axis。text = element_blank(), axis。ticks = element_blank(), axis。title = element_blank(), plot。title = element_text(size = 10, hjust = 0。5), plot。margin = unit(c(-0。5, -0。5, -0。5, -0。5), “inches”), #設定影象輸出的邊緣距離 legend。position = “bottom”) #設定圖例位於影象正下方ggsave(“2018年世界各國制定與執行促進私營部門發展能力的評估。jpg”,dpi=1000,width=13,height=12) #輸出寬為13cm,長為12cm,dpi為1000的jpg格式圖片並儲存

如何用R語言繪製並填充相對正確的世界地圖

繪製填充顏色的世界地圖效果圖

由於這裡的shape檔案採用的是普通圓柱投影,看起來會比較扁。但是我們對比自然資源部提供的帶審圖號的例圖可以發現此時輸出的影象除了沒有南極洲外,在總體上已經達到了和例圖比較接近的程度。但是請注意,千萬不要以為此時已經大功告成了,這裡直接輸出的地圖只是在總體上接近,還遠遠沒有達到透過稽核的標準。

如何用R語言繪製並填充相對正確的世界地圖

自然資源部提供的例圖

為什麼呢?這就呼應了我們反覆強調的“相對正確”一詞。請仔細閱讀自然資源部例圖中關於國家邊界的劃線,特別需要注意朝鮮半島、克什米爾地區、中東以及非洲大陸國家邊界的劃線(通常都是未定界限)。這些細緻的工作就需要在Adobe Illustrator等專業軟體中完成了。

同樣,我們還可以對投影視角進行變換,下圖顯示的是亞洲視角:

# Asia ggplot() + geom_sf(data = worlddata,aes(fill = estimate),colour = “#525252”,size=0。3)+ geom_sf(data = SCSislands,colour = “#525252”)+ geom_sf(data = NineDashLine,color = “#525252”,size=0。3)+ scale_fill_gradient(low=“#deebf7”,high=“#4292c6”)+ coord_sf(crs= “+proj=ortho +lat_0=20 +lon_0=90”)+ guides(fill=guide_legend(title=‘評估指數’))+ ggtitle(“2018年世界各國制定與執行促進私營部門發展能力的評估(亞洲視角)”)+ theme(panel。grid = element_blank(), panel。background = element_rect(fill = “Aliceblue”), axis。text = element_blank(), axis。ticks = element_blank(), axis。title = element_blank(), plot。title = element_text(size = 15, hjust = 0。5), legend。position = “right”)ggsave(“2018年世界各國制定與執行促進私營部門發展能力的評估(亞洲視角)。jpg”,dpi=1000,width=15,height=12)

如何用R語言繪製並填充相對正確的世界地圖

亞洲視角

而這行程式碼顯示的則是北極視角:

# North Pole ggplot() + geom_sf(data = worlddata,aes(fill = estimate),colour = “#525252”,size=0。3)+ geom_sf(data = SCSislands,colour = “#525252”)+ geom_sf(data = NineDashLine,color = “#525252”,size=0。3)+ coord_sf(crs = “+proj=laea +lat_0=52 + lon_0=10 + x_0=4321000 + y_0=3210000 + ellps = GRS80 + units = m + no_defs”)+ scale_fill_gradient(low = “#deebf7”,high = “#4292c6”)+ guides(fill=guide_legend(title=‘評估指數’))+ ggtitle(“2018年世界各國制定與執行促進私營部門發展能力的評估(北極視角)”)+ theme(panel。grid = element_blank(), panel。background = element_rect(fill = “Aliceblue”), axis。text = element_blank(), axis。ticks = element_blank(), axis。title = element_blank(), plot。title = element_text(size=15, hjust=0。5, vjust=0。5), legend。position = “right”)ggsave(“2018年世界各國制定與執行促進私營部門發展能力的評估(北極視角)。jpg”,dpi=1000,width=15,height=12)

如何用R語言繪製並填充相對正確的世界地圖

北極視角

總而言之,在R中實現地圖的資料視覺化是一項非常有趣的過程。這一過程雖然十分繁瑣,但是可以為我們在從事科研寫作的過程中實現地理資訊的視覺化提供便利,從而增強讀者的閱讀體驗。需要坦誠的是,作為非地理專業的學生,我們對地圖繪製的理解是十分粗淺的,同時我們找到的這個shape檔案肯定不是最好的,我們歡迎各位使用者與我們分享更適合國內投稿的shape檔案,也虛心接受任何善意的批評。

最後,我們將本文的相關地圖shape檔案以及案例資料檔案都存入網盤,感興趣的讀者朋友可以點選擴充套件連結進行下載複驗(提取碼為wv07)。未來我們還將與大家分享如何繪製並填充以0°經線為中心的世界地圖、當代中國地圖和中國歷史地圖的經驗,歡迎繼續關注我們。

參考文獻:

[1] World map and Map projections,https://semba-blog。netlify。app/01/26/2020/world-map-and-map-projections/

[2] How to plot a full hemispheric orthographic projection in R, https://gis。stackexchange。com/questions/115818/how-to-plot-a-full-hemispheric-orthographic-projection-in-r

[3] 《以中國為中心Echart世界地圖例項》,https://download。csdn。net/download/liming1016/12718849

[4] 自然資源部地圖技術審查中心:《地圖表示錯誤例項》,https://www。zrzyst。cn/dtbscwsl/index。jhtml

致謝:

感謝周源(神戶大學政治學博士生、政文觀止Poliview特邀作者)在本文寫作過程中給予的寶貴建議。

撰文:

楊端程