1. 程式人生 > >(在模仿中精進資料視覺化06)常見抽象地圖的製作方法

(在模仿中精進資料視覺化06)常見抽象地圖的製作方法

> 本文完整程式碼及資料已上傳至我的`Github`倉庫[https://github.com/CNFeffery/FefferyViz](https://github.com/CNFeffery/FefferyViz) # 1 簡介   我們經常會在一些**PPT報告**或者**宣傳廣告**中看到一些比較抽象的地圖,它們都是在正常地圖的基礎上,通過置換幾何元素,來實現出較為抽象的效果,這類的作品非常之多,因此本文不模仿實際的某幅作品,而是製作出下面三類抽象地圖:
圖1
# 2 基於Python模仿常見抽象地圖   對應圖1,我們下面來分別模仿3類抽象地圖,首先準備一下要用到的中國地圖資料,我們偷個懶直接使用高德開源的地圖資料介面:
圖2
  為了方便和簡化之後的運算,我們利用`unary_union`來將融合所有要素為一個:
圖3
  這樣我們的基礎資料就準備好了~ ## 2.1 向外環形擴散的地圖   首先我們來製作圖1左圖所示,從以某個點為圓心,向外環形擴散的地圖,原理其實很簡單,只需要定義圓心座標,接著向外按照等差數列,依次擴大半徑距離計算緩衝區的輪廓線: ```Python from shapely.geometry import Point import matplotlib.pyplot as plt fig, ax = plt.subplots(figsize=(8, 8)) # 以重慶為圓心,生成向外的環形線,間隔為80公里 center = gpd.GeoSeries([Point((106.546737, 29.566598))], crs='EPSG:4326').to_crs(albers_proj) circles = gpd.GeoSeries([center[0].buffer(i*1000*80).boundary for i in range(1, 45)], crs=albers_proj) ax = china_total.plot(ax=ax, facecolor='none', edgecolor='black') ax = circles.plot(ax=ax) ```
圖4
  可以看到目前生成的環形線已經可以覆蓋中國全境,最後用`china_total`來裁剪即可: ```Python fig, ax = plt.subplots(figsize=(8, 8)) # 用china_total作為蒙版從circles中裁切出繪圖所需部分 ax = gpd.clip(circles, mask=china_total).plot(ax=ax, color='white') ax.set_facecolor('#4a4db7') fig.set_facecolor('#4a4db7') ax.set_xticks([]) ax.set_yticks([]) ax.spines['left'].set_color('none') ax.spines['top'].set_color('none') ax.spines['right'].set_color('none') ax.spines['bottom'].set_color('none') fig.savefig('圖5.png', dpi=500, bbox_inches='tight', pad_inches=0) ```
圖5
  在這幅圖的基礎上,你就可以新增其他的文字標註等元素,形成配圖,使得你的報告更加高階。 ## 2.2 畫素風格地圖   接著我們來製作圖1中圖所示的又方塊組成的畫素風格地圖,原理也很簡單,生成覆蓋`china_total`範圍的網格: ```Python from shapely.geometry import MultiLineString from shapely.ops import polygonize # 用於將交叉線轉換為網格面 import numpy as np # 提取china_total左下角與右上角座標 xmin, ymin, xmax, ymax = china_total.total_bounds xmin, ymin, xmax, ymax = int(xmin), int(ymin), int(xmax), int(ymax) # 建立x方向上的所有座標位置,間距50公里 x = np.arange(xmin, xmax, 50*1000) # 建立y方向上的所有座標位置,間距50公里 y = np.arange(ymin, ymax, 50*1000) # 生成全部交叉線座標資訊 hlines = [((x1, yi), (x2, yi)) for x1, x2 in zip(x[:-1], x[1:]) for yi in y] vlines = [((xi, y1), (xi, y2)) for y1, y2 in zip(y[:-1], y[1:]) for xi in x] grids = gpd.GeoSeries(list(polygonize(MultiLineString(hlines + vlines))), crs=albers_proj) grids.plot(facecolor='none', edgecolor='black') ```
圖6
  再向內緩衝一定的距離,即可得到結果:
圖7
## 2.3 由不規則多邊形拼湊的地圖   最後我們來製作圖1右圖所示的由不規則多邊形拼湊的地圖,需要用到**泰森多邊形**,我們可以通過`pip install geovoronoi`來安裝輔助庫。   因為泰森多邊形需要從點出發建立多邊形,因此我們可以生成目標面內部的隨機散點,再作為輸入來生成所需的多邊形: ```Python from geovoronoi import voronoi_regions_from_coords np.random.seed(42) coords = gpd.GeoSeries([Point(x, y) for x, y in zip(np.random.uniform(xmin, xmax, 1000), np.random.uniform(ymin, ymax, 1000))], crs=albers_proj) # 得到china_total內部的散點座標陣列 coords = coords[coords.within(china_total[0])] # 利用geovoronoi得到所需的泰森多邊形,其中poly_shapes即為我們需要的多邊形 poly_shapes, pts, poly_to_pt_assignments = voronoi_regions_from_coords(np.array(coords.apply(lambda g: (g.x, g.y)).tolist()), china_total[0]) fig, ax = plt.subplots(figsize=(8, 8)) ax = china_total.plot(ax=ax, facecolor='none', edgecolor='white', linewidth=0.5) ( gpd .GeoSeries(poly_shapes) .buffer(-10*1000) .plot(ax=ax, facecolor='white', linewidth=0.2) ) ax.set_xticks([]) ax.set_yticks([]) ax.set_facecolor('#4a4db7') fig.set_facecolor('#4a4db7') ax.spines['left'].set_color('none') ax.spines['top'].set_color('none') ax.spines['right'].set_color('none') ax.spines['bottom'].set_color('none') fig.savefig('圖8.png', dpi=500, bbox_inches='tight', pad_inches=0) ```
圖8
---   以上就是本文的全部內容,歡迎在評論區與我進