如何使用 Basemap (Python) 绘制美国的 50 个州?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39742305/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 22:39:06  来源:igfitidea点击:

How to use Basemap (Python) to plot US with 50 states?

pythonmatplotlibmatplotlib-basemap

提问by MomoPP

I am aware that the powerful package Basemapcan be utilized to plot US map with state boundaries. I have adapted this example from Basemap GitHubrepository to plot 48 states colored by their respective population density: enter image description here

我知道强大的Basemap包可用于绘制带有州界的美国地图。我已经改编了 Basemap GitHub存储库中的这个示例,以绘制按各自人口密度着色的 48 个州: 在此处输入图片说明

Now my question is: Is there a simple way to add Alaska and Hawaii to this map and place those at a custom location, e.g. bottom left corner? Something like this:

现在我的问题是:是否有一种简单的方法可以将阿拉斯加和夏威夷添加到该地图并将它们放置在自定义位置,例如左下角?像这样的东西:

enter image description here

在此处输入图片说明

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap as Basemap
from matplotlib.colors import rgb2hex
from matplotlib.patches import Polygon
# Lambert Conformal map of lower 48 states.
m = Basemap(llcrnrlon=-119,llcrnrlat=22,urcrnrlon=-64,urcrnrlat=49,
        projection='lcc',lat_1=33,lat_2=45,lon_0=-95)
# draw state boundaries.
# data from U.S Census Bureau
# http://www.census.gov/geo/www/cob/st2000.html
shp_info = m.readshapefile('st99_d00','states',drawbounds=True)
# population density by state from
# http://en.wikipedia.org/wiki/List_of_U.S._states_by_population_density
popdensity = {
'New Jersey':  438.00,
'Rhode Island':   387.35,
'Massachusetts':   312.68,
'Connecticut':    271.40,
'Maryland':   209.23,
'New York':    155.18,
'Delaware':    154.87,
'Florida':     114.43,
'Ohio':  107.05,
'Pennsylvania':  105.80,
'Illinois':    86.27,
'California':  83.85,
'Hawaii':  72.83,
'Virginia':    69.03,
'Michigan':    67.55,
'Indiana':    65.46,
'North Carolina':  63.80,
'Georgia':     54.59,
'Tennessee':   53.29,
'New Hampshire':   53.20,
'South Carolina':  51.45,
'Louisiana':   39.61,
'Kentucky':   39.28,
'Wisconsin':  38.13,
'Washington':  34.20,
'Alabama':     33.84,
'Missouri':    31.36,
'Texas':   30.75,
'West Virginia':   29.00,
'Vermont':     25.41,
'Minnesota':  23.86,
'Mississippi':   23.42,
'Iowa':  20.22,
'Arkansas':    19.82,
'Oklahoma':    19.40,
'Arizona':     17.43,
'Colorado':    16.01,
'Maine':  15.95,
'Oregon':  13.76,
'Kansas':  12.69,
'Utah':  10.50,
'Nebraska':    8.60,
'Nevada':  7.03,
'Idaho':   6.04,
'New Mexico':  5.79,
'South Dakota':  3.84,
'North Dakota':  3.59,
'Montana':     2.39,
'Wyoming':      1.96,
'Alaska':     0.42}
# choose a color for each state based on population density.
colors={}
statenames=[]
cmap = plt.cm.hot # use 'hot' colormap
vmin = 0; vmax = 450 # set range.
for shapedict in m.states_info:
    statename = shapedict['NAME']
    # skip DC and Puerto Rico.
    if statename not in ['District of Columbia','Puerto Rico']:
        pop = popdensity[statename]
        # calling colormap with value between 0 and 1 returns
        # rgba value.  Invert color range (hot colors are high
        # population), take sqrt root to spread out colors more.
        colors[statename] = cmap(1.-np.sqrt((pop-vmin)/(vmax-vmin)))[:3]
    statenames.append(statename)
# cycle through state names, color each one.
ax = plt.gca() # get current axes instance
for nshape,seg in enumerate(m.states):
    # skip DC and Puerto Rico.
    if statenames[nshape] not in ['District of Columbia','Puerto Rico']:
        color = rgb2hex(colors[statenames[nshape]]) 
        poly = Polygon(seg,facecolor=color,edgecolor=color)
        ax.add_patch(poly)
plt.title('Filling State Polygons by Population Density')
plt.show()

回答by MomoPP

For anyone interested, I was able to fix it myself. The (x,y) coordinates of each segment (for Alaska and Hawaii) should be translated. I also scale down Alaska to 35% before translating it.

对于任何有兴趣的人,我都可以自己修复它。每个线段(阿拉斯加和夏威夷)的 (x,y) 坐标应该被转换。在翻译之前,我还将阿拉斯加缩小到 35%。

The second for-loop should be modified as following:

第二个 for 循环应修改如下:

for nshape,seg in enumerate(m.states):
    # skip DC and Puerto Rico.
    if statenames[nshape] not in ['Puerto Rico', 'District of Columbia']:
    # Offset Alaska and Hawaii to the lower-left corner. 
        if statenames[nshape] == 'Alaska':
        # Alaska is too big. Scale it down to 35% first, then transate it. 
            seg = list(map(lambda (x,y): (0.35*x + 1100000, 0.35*y-1300000), seg))
        if statenames[nshape] == 'Hawaii':
            seg = list(map(lambda (x,y): (x + 5100000, y-900000), seg))

        color = rgb2hex(colors[statenames[nshape]]) 
        poly = Polygon(seg,facecolor=color,edgecolor=color)
        ax.add_patch(poly)

Here is the new US map (using the 'Greens' colormap).

这是新的美国地图(使用“绿色”颜色图)。

enter image description here

在此处输入图片说明

回答by Valerie R. Coffman

The above answer is great and was very helpful for me.

上面的答案很好,对我很有帮助。

I noticed that there are many tiny islands that extend for many miles beyond the 8 main islands of Hawaii. These create little dots in Arizona, California, and Oregon, (or Nevada and Idaho) depending on how you translated Hawaii. To remove these, you need a condition on the area of the polygon. It's helpful to do one loop through the states_infoobject to do this:

我注意到有许多小岛在夏威夷的 8 个主要岛屿之外延伸了许多英里。这些会在亚利桑那州、加利福尼亚州和俄勒冈州(或内华达州和爱达荷州)创建小点,具体取决于您如何翻译夏威夷。要删除这些,您需要多边形区域的条件。对states_info对象执行一次循环来执行此操作会很有帮助:

# Hawaii has 8 main islands but several tiny atolls that extend for many miles.
# This is the area cutoff between the 8 main islands and the tiny atolls.
ATOLL_CUTOFF = 0.005

m = Basemap(llcrnrlon=-121,llcrnrlat=20,urcrnrlon=-62,urcrnrlat=51,
    projection='lcc',lat_1=32,lat_2=45,lon_0=-95)

# load the shapefile, use the name 'states'
m.readshapefile('st99_d00', name='states', drawbounds=True)

ax = plt.gca()


for i, shapedict in enumerate(m.states_info):
    # Translate the noncontiguous states:
    if shapedict['NAME'] in ['Alaska', 'Hawaii']:
        seg = m.states[int(shapedict['SHAPENUM'] - 1)]
        # Only include the 8 main islands of Hawaii so that we don't put dots in the western states.
        if shapedict['NAME'] == 'Hawaii' and float(shapedict['AREA']) > ATOLL_CUTOFF:
            seg = list(map(lambda (x,y): (x + 5200000, y-1400000), seg))
        # Alaska is large. Rescale it.
        elif shapedict['NAME'] == 'Alaska':
            seg = list(map(lambda (x,y): (0.35*x + 1100000, 0.35*y-1300000), seg))
        poly = Polygon(seg, facecolor='white', edgecolor='black', linewidth=.5)
        ax.add_patch(poly)