(在模仿中精進資料視覺化06)常見抽象地圖的製作方法
阿新 • • 發佈:2021-01-03
> 本文完整程式碼及資料已上傳至我的`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
---
以上就是本文的全部內容,歡迎在評論區與我進