四色地圖繪製方式

在圖論(graph theory)與地圖學(cartography)中,「四色定理(Four Color Theorem)」與「五色定理(Five Color Theorem)」是兩項經典的重要命題。四色定理指出,任意一張平面地圖,只需使用四種顏色,就能保證所有相鄰區域都不會使用相同顏色,是1852年由數學家賈斯禮(Francis Guthrie)首次提出四色定理的猜想,雖然從地圖設計的實務上確實能僅用四種顏色就把地圖著色,且相鄰不同色,但一直與無法用數學方式證明它,直到 1976 年由 Appel 與 Haken 借助電腦演算法輔助(暴力窮舉法)成功證明,成為數學史上首例以電腦完成的證明之一。

四色地圖的案例

在四色定理尚未被正式證明前,數學家 Heawood 於 1890 年提出了較為保守但易於證明的五色定理,主張任意平面圖最多使用五種顏色也可避免相鄰區域顏色重複。五色定理雖非最精簡解法,卻在地圖設計實務上提供了一項重要保證,特別適用於複雜地圖或圖層自動著色演算法中。

目前在QGIS 3.x版中內建有拓撲著色(Topological coloring)功能,但因演算法設計需求而採用最多五色完成著色任務,即使理論上四色已經足夠,以下為簡要操作說明:

  1. Processing -> Toolbox 搜尋 Topological coloring 功能

2.指定一個多邊形向量圖層(例如行政區劃),以及最少使用顏色數量,演算法就會自動分類(在屬性資料表新增一個color_id欄位,並給予不同的分類代號)。

3.程式將建立一個新圖層,新增一個名為 color_id 的欄位,但顏色仍與原圖層相同;接著,編輯這個新圖層的圖層屬性,進入「圖徵(Symbology)」分頁進行細部設定:

  • 在最上方選擇「分類式(Categorized)」樣式。
  • 將分類欄位設為 color_id
  • 點擊「分類(Classify)」按鈕,以建立分類並自動指派對應顏色。
  • 修改個別分類(代號)的顏色。
臺北四色地圖

4.同樣操作也可以運用到臺灣縣市行政區域圖。

臺灣四色地圖

5.受限於演算法因素,拓撲著色(Topological coloring)功能,針對比較複雜的多邊形(存在 MultiPolygon幾何、飛地等情況),最終分類(顏色)數量可能會大於4,成為五色或六色地圖。

臺灣六色地圖

6.如果可以接受少量的相鄰多邊形有相同顏色情況,可以利用ChatGPT可以產生Python 程式,用來自動為多邊形圖層加上「四色理論」分類欄位,限制只用 4 色完成配色:

  • 依據圖形間的接觸關係(例如鄰接的鄉鎮)建立一個鄰接圖。
  • 從圖層中心位置(如中央山脈)開始進行顏色分配,往外擴散,有助於減少顏色衝突。
  • 每個多邊形會被分配一個 color_id 整數欄位(值為 1~4),盡可能確保相鄰的多邊形不會有相同顏色
  • 程式使用了 NetworkX 處理拓撲關係,運算快速、穩定,適合上百筆資料的地圖。
import networkx as nx
from qgis.core import (
QgsProject, QgsField, QgsSpatialIndex, QgsFeature, QgsGeometry, QgsPointXY
)
from PyQt5.QtCore import QVariant

layer = iface.activeLayer()
if not layer or layer.geometryType() != 2:
raise Exception("請選取一個多邊形圖層")

# 新增 color_id 欄位
layer.startEditing()
if 'color_id' not in [f.name() for f in layer.fields()]:
layer.dataProvider().addAttributes([QgsField('color_id', QVariant.Int)])
layer.updateFields()

# 建立要素快取與空間索引
features = {f.id(): f for f in layer.getFeatures()}
index = QgsSpatialIndex()
for feat in features.values():
index.insertFeature(feat)

# 建立鄰接圖
G = nx.Graph()
for fid, feat in features.items():
G.add_node(fid)
neighbor_ids = index.intersects(feat.geometry().boundingBox())
for nid in neighbor_ids:
if nid != fid and feat.geometry().touches(features[nid].geometry()):
G.add_edge(fid, nid)

# 計算圖層中心點
layer_center = layer.extent().center()
center_geom = QgsGeometry.fromPointXY(QgsPointXY(layer_center))

# 根據與中心距離排序
def dist_to_center(feat):
return feat.geometry().centroid().distance(center_geom)

sorted_nodes = sorted(G.nodes, key=lambda fid: dist_to_center(features[fid]))

# 自行進行貪婪著色(最多使用 4 色)
coloring = {}
for fid in sorted_nodes:
neighbor_colors = {coloring[n] for n in G.neighbors(fid) if n in coloring}
for color in range(1, 5): # 限定四色
if color not in neighbor_colors:
coloring[fid] = color
break

# 寫入 color_id
field_idx = layer.fields().indexFromName('color_id')
for fid, color in coloring.items():
layer.changeAttributeValue(fid, field_idx, color)

layer.commitChanges()
print(f"完成!已從圖層中心開始排序並套用四色著色,共使用顏色:{max(coloring.values())}")
臺灣四色地圖

進階閱讀: