简体   繁体   English

为什么matplotlib底图没有绘制地图中某些区域的颜色?

[英]Why is matplotlib basemap not plotting the colours of some areas in my map?

The code below is supposed to colour all the states of Vietnam: 下面的代码应该为越南的所有州着色:

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()

But this produces the map below, where some of the states are not coloured even though they are present in the state names and in the subdivisions: 但是这会产生下面的地图,其中一些状态没有着色,即使它们存在于州名和细分中:

在此输入图像描述

In fact, if I try to colour a state whose name is not present in the lists, it throws an error: 实际上,如果我尝试为列表中不存在其名称的状态着色,则会引发错误:

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

So, clearly the states that are not colored are present in the list, as I'm not getting any error. 因此,显然列表中存在未着色的状态,因为我没有收到任何错误。 So, what's going on? 发生什么了?

EDIT: It just struck me that almost all the states that aren't coloured share at least some part of their border with sea/ocean in the real world. 编辑:让我感到震惊的是,几乎所有没有颜色的州至少在现实世界中与海洋的一部分共享。 The 6 exceptions are highlighted in red below: 以下红色突出显示了6个例外情况:

在此输入图像描述

Now that's very interesting! 现在这很有趣! Could it have anything to do with the issue? 它与这个问题有什么关系吗? If yes, what? 如果有,那是什么? And why? 为什么? And why do those 6 exceptions exist? 为什么存在这6个例外?

EDIT 2: I get similar results when drawing the map of Philippines: 编辑2:我在绘制菲律宾地图时获得了类似的结果:

在此输入图像描述

In shapefiles , a country/province/whatever, may be broken down into several line segments. shapefiles ,国家/省/无论如何,可以分成几个线段。 Why that is, I don't know, but in order to plot the shape correctly, you need to use all the necessary segments. 为什么会这样,我不知道,但为了正确绘制形状,您需要使用所有必要的段。 Actually, in the Basemap documentation for shapefiles there is an example under 'filling polygons', how to do this correctly. 实际上,在shapefile底图文档中,在“填充多边形”下有一个示例,如何正确执行此操作。 I adapted their example to your use case. 我将他们的例子改编为你的用例。 It's probably not the most optimal solution, but it seems to work. 它可能不是最理想的解决方案,但似乎有效。

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()

The result looks as expected: 结果看起来像预期的那样:

上述代码的结果

Note that I could only test the code under Python 3.6, so there might be some adjustments necessary. 请注意,我只能在Python 3.6下测试代码,因此可能需要进行一些调整。 Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM