Почему базовая карта matplotlib не отображает цвета некоторых областей на моей карте?
Код ниже должен раскрасить все штаты Вьетнама:
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
fig, ax = plt.subplots(figsize=(10,20))
# create the map
map = Basemap(resolution='l', # c, l, i, h, f or None
projection='merc',
lat_0=15.95, lon_0=105.85,
llcrnrlon=102., llcrnrlat= 8.31, urcrnrlon=109.69, urcrnrlat=23.61)
# load the shapefile, use the name 'states'
map.readshapefile(r'path\to\gadm36_VNM_1', name='states', drawbounds=True)
# shapefile downloaded from http://www.gadm.org/
# collect the state names from the shapefile attributes so we can
# look up the shape obect for a state by it's name
state_names = []
for shape_dict in map.states_info:
state_names.append(shape_dict['VARNAME_1'])
ax = plt.gca() # get current axes instance
# NOR, CEN, SOU and MEK are some subdivisions I have created for the states of Vietnam
NOR = ['Lai Chau',
'Lao Cai',
'Ha Giang',
'Cao Bang',
'Dien Bien',
'Son La',
'Yen Bai',
'Tuyen Quang',
'Bac Kan',
'Lang Son',
'Thai Nguyen',
'Phu Tho',
'Vinh Phuc',
'Hoa Binh',
'Ha Noi',
'Bac Ninh',
'Hai Duong',
'Hung Yen',
'Ha Nam',
'Quang Ninh',
'Hai Phong',
'Thai Binh',
'Nam Dinh',
'Bac Giang',
'Ninh Binh']
CEN = ['Thanh Hoa',
'Nghe An',
'Ha Tinh',
'Quang Binh',
'Quang Tri',
'Thua Thien Hue',
'Da Nang']
SOU = ['Quang Nam',
'Kon Tum',
'Quang Ngai',
'Gia Lai',
'Binh Dinh',
'Dak Lak',
'Phu Yen',
'Khanh Hoa',
'Dak Nong',
'Lam Dong',
'Ninh Thuan']
MEK = ['Binh Phuoc',
'Dong Nai',
'Binh Thuan',
'Tay Ninh',
'Binh Duong',
'Dong Nai',
'Ba Ria - Vung Tau',
'Ho Chi Minh',
'Long An',
'An Giang',
'Dong Thap',
'Tien Giang',
'Kien Giang',
'Can Tho',
'Vinh Long',
'Ben Tre',
'Hau Giang',
'Tra Vinh',
'Soc Trang',
'Bac Lieu',
'Ca Mau']
# Define the colours to be used to colour the states
from matplotlib import cm
from numpy import linspace
start = 0.5
stop = 1.0
number_of_lines= 4
cm_subsection = linspace(start, stop, number_of_lines)
cm_subsection[0] = cm_subsection[0]*4
cm_subsection[1] = cm_subsection[1]*0.6
cm_subsection[2] = cm_subsection[2]*0.8
cm_subsection[3] = cm_subsection[3]*0.1
colors = [ cm.Blues(x) for x in cm_subsection ]
for state in NOR:
seg = map.states[state_names.index(state)]
poly = Polygon(seg, facecolor=colors[0], edgecolor=colors[0])
ax.add_patch(poly)
for state in CEN:
seg = map.states[state_names.index(state)]
poly = Polygon(seg, facecolor=colors[1], edgecolor=colors[1])
ax.add_patch(poly)
for state in SOU:
seg = map.states[state_names.index(state)]
poly = Polygon(seg, facecolor=colors[2], edgecolor=colors[2])
ax.add_patch(poly)
for state in MEK:
seg = map.states[state_names.index(state)]
poly = Polygon(seg, facecolor=colors[3], edgecolor=colors[3])
ax.add_patch(poly)
import matplotlib.patches as mpatches
NOR_patch = mpatches.Patch(color=colors[0], label='Rate: 34.85%')
CEN_patch = mpatches.Patch(color=colors[1], label='Rate: 25.61%')
SOU_patch = mpatches.Patch(color=colors[2], label='Rate: 32.66%')
MEK_patch = mpatches.Patch(color=colors[3], label='Rate: 20.02%')
plt.legend(handles=[NOR_patch, CEN_patch, SOU_patch, MEK_patch])
plt.show()
Но это приводит к приведенной ниже карте, где некоторые из штатов не окрашены, даже если они присутствуют в названиях штатов и в подразделениях:
Фактически, если я пытаюсь раскрасить состояние, имя которого отсутствует в списках, оно выдает ошибку:
MEK.append('ABCDE')
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-619-a89da62a0831> in <module>()
134
135 for state in MEK:
--> 136 seg = map.states[state_names.index(state)]
137 poly = Polygon(seg, facecolor=colors[3], edgecolor=colors[3])
138 ax.add_patch(poly)
ValueError: 'ABCDE' is not in list
Итак, ясно, что в списке присутствуют неокрашенные состояния, поскольку я не получаю никакой ошибки. Так, что происходит?
РЕДАКТИРОВАТЬ: Меня просто поразило, что почти все неокрашенные государства разделяют, по крайней мере, некоторую часть своей границы с морем / океаном в реальном мире. 6 исключений выделены красным цветом ниже:
Теперь это очень интересно! Может ли это иметь какое-либо отношение к проблеме? Если да, то что? И почему? И почему существуют эти 6 исключений?
РЕДАКТИРОВАТЬ 2: я получаю аналогичные результаты при рисовании карты Филиппин:
1 ответ
В shapefiles
, страна / провинция / что угодно, может быть разбита на несколько отрезков. Почему, я не знаю, но для правильного построения формы вам нужно использовать все необходимые сегменты. На самом деле, в документации Базовой карты для шейп-файлов есть пример под "заливкой полигонов", как это сделать правильно. Я адаптировал их пример к вашему случаю использования. Это, вероятно, не самое оптимальное решение, но, похоже, оно работает.
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
from matplotlib import patches as mpatches
from matplotlib import cm
from numpy import linspace
import matplotlib.patches as mpatches
from matplotlib.collections import PatchCollection
fig, ax = plt.subplots(figsize=(4,8))
# create the map
map = Basemap(resolution='l', # c, l, i, h, f or None
projection='merc',
lat_0=15.95, lon_0=105.85,
llcrnrlon=102., llcrnrlat= 8.31, urcrnrlon=109.69, urcrnrlat=23.61)
# load the shapefile, use the name 'states'
map.readshapefile(r'shapefiles/gadm36_VNM_1', name='states', drawbounds=True)
# shapefile downloaded from http://www.gadm.org/
# collect the state names from the shapefile attributes so we can
# look up the shape obect for a state by it's name
state_names = []
for shape_dict in map.states_info:
state_names.append(shape_dict['VARNAME_1'])
ax = plt.gca() # get current axes instance
# NOR, CEN, SOU and MEK are some subdivisions I have created for the states of Vietnam
NOR = ['Lai Chau',
'Lao Cai',
'Ha Giang',
'Cao Bang',
'Dien Bien',
'Son La',
'Yen Bai',
'Tuyen Quang',
'Bac Kan',
'Lang Son',
'Thai Nguyen',
'Phu Tho',
'Vinh Phuc',
'Hoa Binh',
'Ha Noi',
'Bac Ninh',
'Hai Duong',
'Hung Yen',
'Ha Nam',
'Quang Ninh',
'Hai Phong',
'Thai Binh',
'Nam Dinh',
'Bac Giang',
'Ninh Binh']
CEN = ['Thanh Hoa',
'Nghe An',
'Ha Tinh',
'Quang Binh',
'Quang Tri',
'Thua Thien Hue',
'Da Nang']
SOU = ['Quang Nam',
'Kon Tum',
'Quang Ngai',
'Gia Lai',
'Binh Dinh',
'Dak Lak',
'Phu Yen',
'Khanh Hoa',
'Dak Nong',
'Lam Dong',
'Ninh Thuan']
MEK = ['Binh Phuoc',
'Dong Nai',
'Binh Thuan',
'Tay Ninh',
'Binh Duong',
'Dong Nai',
'Ba Ria - Vung Tau',
'Ho Chi Minh',
'Long An',
'An Giang',
'Dong Thap',
'Tien Giang',
'Kien Giang',
'Can Tho',
'Vinh Long',
'Ben Tre',
'Hau Giang',
'Tra Vinh',
'Soc Trang',
'Bac Lieu',
'Ca Mau']
# Define the colours to be used to colour the states
start = 0.5
stop = 1.0
number_of_lines= 4
cm_subsection = linspace(start, stop, number_of_lines)
cm_subsection[0] = cm_subsection[0]*4
cm_subsection[1] = cm_subsection[1]*0.6
cm_subsection[2] = cm_subsection[2]*0.8
cm_subsection[3] = cm_subsection[3]*0.1
colors = [ cm.Blues(x) for x in cm_subsection ]
##collecting the line segments for the provinces:
patches = {state: [] for state in NOR+CEN+SOU+MEK}
for info, shape in zip(map.states_info, map.states):
for state in NOR+CEN+SOU+MEK:
if info['VARNAME_1'] == state:
patches[state].append(mpatches.Polygon(
shape, True,
))
##coloring the the provinces by group:
for state in NOR:
ax.add_collection(PatchCollection(
patches[state], facecolor = colors[0], edgecolor=colors[0]
))
for state in CEN:
ax.add_collection(PatchCollection(
patches[state], facecolor = colors[1], edgecolor=colors[1]
))
for state in SOU:
ax.add_collection(PatchCollection(
patches[state], facecolor = colors[2], edgecolor=colors[2]
))
for state in MEK:
ax.add_collection(PatchCollection(
patches[state], facecolor = colors[3], edgecolor=colors[3]
))
NOR_patch = mpatches.Patch(color=colors[0], label='Rate: 34.85%')
CEN_patch = mpatches.Patch(color=colors[1], label='Rate: 25.61%')
SOU_patch = mpatches.Patch(color=colors[2], label='Rate: 32.66%')
MEK_patch = mpatches.Patch(color=colors[3], label='Rate: 20.02%')
plt.legend(handles=[NOR_patch, CEN_patch, SOU_patch, MEK_patch])
plt.show()
Результат выглядит как и ожидалось:
Обратите внимание, что я мог тестировать код только под Python 3.6, поэтому могут потребоваться некоторые корректировки. Надеюсь это поможет.