【matplotlib基礎】--結合地圖

wang_yb發表於2023-09-25

如果分析的資料與地域相關,那麼,把分析結果結合地圖一起展示的話,會讓視覺化的效果得到極大的提升。

比如,分析各省GDP資料,人口資料,用柱狀圖,餅圖之類的雖然都可以展示分析結果,
不過,如果能在全國的地圖上展示各省的分析結果的話,會讓人留下更加深刻的印象。

將資料的分析結果展示在地圖上,難點在於:

  1. 如何繪製地圖,地圖是展示資料的基礎,如何繪製出需要的地圖區域是第一步
  2. 資料和地圖關聯,資料最終要顯示在地圖上,資料如何與地理座標關聯也是重要的一步
  3. 地圖上展示資料,也就是要在地圖上繪製不同的顏色或者幾何形狀來表達不同的資料

解決了上面3個難題,就能夠結合地圖做一些基本的資料展示了。
本篇透過一個基於南京各個區地理資訊的分析示例,來演示如何一步步透過地圖來展示分析結果。

1. 繪製地圖

第一步是繪製地圖,其實地圖就是一塊塊不規則的多邊形拼接起來的。
在本篇的示例中,各個多邊形就是南京的各個區

繪製多邊形不難,難的是如何得到各個多邊形的頂點座標。
好在現在有很多的開放地理資訊平臺,可以讓我們獲取到想要的地理資訊。

1.1. 獲取地理資訊

比如,透過阿里的DataV資料視覺化平臺,可以獲取南京各個區的地理範圍資訊。
image.png
在這個平臺上,左邊選擇區域,右邊會生成對應範圍的地理資訊的資料。
地理資訊資料是json格式。

1.2. 展示地理資訊

為了讀取地理資訊資料並展示,需要用到一個 GeoPandas 的庫。
pip 安裝很簡單:

$ pip install geopandas

geopandas可以直接讀取DataV資料視覺化平臺生成的JSON資料並展示。

import geopandas as gpd

df_geo = gpd.read_file(
    "https://geo.datav.aliyun.com/areas_v3/bound/320100_full.json"
)
df_geo

image.png
json檔案的HTTP地址DataV資料視覺化平臺就是在上生成的。
這個檔案中的關鍵欄位就是 geometry,其中的內容就是各個區的多邊形形狀的各個頂點的經緯度座標。

展示資料:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
fig.set_size_inches(8, 8)

# df_geo就是上面透過geopandas讀取的資料
df_geo.plot(
    ax=ax,
    column="name",
    cmap="plasma",
    edgecolor="k",
    legend=True,
    legend_kwds={"loc": "lower left"}
)
plt.show()

image.png
其中主要引數的含義:

  1. axmatplotlib生成的子圖,這裡就是資料要繪製的位置
  2. column:作為不同區域的名稱,這裡就是南京各個區的名稱
  3. cmap:一組顏色,分別對應不同的區
  4. edgecolor:每個多邊形邊緣的顏色,這裡設定的是黑色
  5. legend:是否顯示圖例
  6. legend_kwds:設定圖例的配置資訊,這裡只設定了圖例的位置

2. 地圖和資料關聯

首先生成一些測試資料:

# 刪除 df_geo 中一些不必要的列
df_geo = df_geo.drop(columns=["childrenNum", "level", "parent", "subFeatureIndex"])

# 南京各個區的名稱
area_names = df_geo.loc[:, "name"]

# df_val為測試資料,其中name列是各個區的名稱
# value 列是一些隨機數,模擬各個區的人口,GDP等資料
df_val = pd.DataFrame({
    "name": area_names.tolist(),
    "value": np.random.randint(10, 10000, len(area_names))
})

測試資料 df_val 模擬其他途徑得到的業務資料,
下面要將 df_val 中的指展示到地圖上,就要先把 df_valdf_geo 結合起來。

# 以 name 列作為結合兩個資料集的依據
df = pd.merge(df_geo, df_val, on="name", how="left")
df

image.png
這樣,我們就得到了同時包含地理資訊(geometry)業務資料(value)的資料集了。

3. 地圖上展示資料

接下來就是展示資料了,下面演示兩種在地圖上展示資料的方式。

3.1. 熱力圖方式

根據 value 值的不同,用漸變色來顯示不同區的顏色。

fig, ax = plt.subplots()
fig.set_size_inches(8, 8)
ax.axis("off")

df.plot(
    ax=ax,
    column="value",
    cmap="plasma",
    edgecolor="k",
    legend=True,
    legend_kwds={'label': "value", 'shrink':0.5},
)

for index in df.index:
    x = df.iloc[index].geometry.centroid.x
    y = df.iloc[index].geometry.centroid.y
    name = df.iloc[index]["name"]
    if name in ["建鄴區", "鼓樓區", "玄武區", "秦淮區"]:
        ax.text(x, y, name, ha="center", va="center", fontsize=8)
    else:
        ax.text(x, y, name, ha="center", va="center")

plt.show()

image.png
其中,"建鄴區", "鼓樓區", "玄武區", "秦淮區" 四個區的面積比較小,
所以字型稍微調小了一些。

3.2. 分類展示

value值分為3類,每類用不同的形式來表示。

  • value < 3000
  • 3000 <= value < 5000
  • value >= 5000
import matplotlib.patches as mpatches

fig, ax = plt.subplots()
fig.set_size_inches(5, 10)
ax.axis("off")
legend_list = []

df[df["value"] < 3000].plot(
    ax=ax,
    color="lightblue",
    edgecolor="k",
    hatch="\\\\",
    legend=False,
)
legend_list.append(
    mpatches.Patch(
        facecolor="lightblue",
        edgecolor="black", hatch="\\\\", label="value<3000"
    )
)


df[(df["value"] >= 3000) & (df["value"] < 5000)].plot(
    ax=ax,
    color="lightgreen",
    edgecolor="k",
    hatch="o",
    legend=False,
)
legend_list.append(
    mpatches.Patch(
        facecolor="lightgreen",
        edgecolor="black", hatch="o", label="3000<=value<5000")
)

df[df["value"] >= 5000].plot(
    ax=ax,
    color="r",
    edgecolor="k",
    hatch="*",
    legend=False,
)
legend_list.append(mpatches.Patch(
    facecolor="r",
    edgecolor="black", hatch="*", label="value>=5000"))

ax.legend(handles = legend_list, 
          loc=(1, 0.5), 
          title="value 等級", 
          fontsize=12)

plt.show()

image.png

4. 總結

結合地理資訊展示資料,讓資料更加的生動,特別是很多資料分析場景本身就和地理資訊密切相關。
除了基於地域的各種經濟或者人口等等的相關資料,
還有各類氣象資料,如能和地理資訊結合展示的話,會讓人對整體情況一目瞭然。

文中用到的主要資源:


相關文章