在地图上绘制不同大小的圆形

4

我有一个如下所示的排序 DataFrame(数字完全是随机的):

In[1]: df
Out[1]:
            Total  Count
Location 1     20      5
Location 2     15      4
Location 3     13      3
...
Location 10     1      1

每个位置都有一个纬度和经度。
我想使用圆圈在地图上绘制这些位置。圆圈的半径需要对应于 “总数” 中的数值大小,也就是说,位置1需要有最大的圆圈,位置2需要有较小的圆圈,依此类推。
另外,我希望颜色可以渐变。最大的圆圈是红色的,下一个是橙色的,再下一个是黄色的,以此类推。
最后,我希望在每个圆圈旁边添加注释。
到目前为止,我已经成功在地图上绘制了蓝色的点,但我不知道如何绘制具有相应大小和颜色的圆圈。
以下是我到目前为止的代码:
m = Basemap(resolution='i', projection='merc', llcrnrlat=49.0, urcrnrlat=52.0, llcrnrlon=1., urcrnrlon=8.0, lat_ts=51.0)
m.drawcountries()
m.drawcoastlines()
m.fillcontinents()

for row_index, row in df.iterrows():
    x, y = db.getLocation(row_index)
    lat, lon = m(y, x)
    m.plot(lat, lon, 'b.', alpha=0.5)
    #This draws blue dots.

plt.title('Top 10 Locations')
plt.show()
1个回答

3
  • The matplotlib scatter function has s and c parameters which would allow you to plot dots of different sizes and colors.

    The Pandas DataFrame.plot method calls the matplotlib scatter function when you specify kind='scatter'. It also passes extra arguments along to the call to scatter so you could use something like

    df.plot(kind='scatter', x='lon', y='lat', s=df['Total']*50, c=df['Total'], cmap=cmap)
    

    to plot your points.

  • Annotating the points can be done with calls to plt.annotate.

  • The gist_rainbow colormap goes from red to orange to yellow ... to violet. gist_rainbow_r is the reversed colormap, which makes red correspond to the largest values.

例如,
import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame({'Total': [20,15,13,1],
                   'lat': [40,0,-30,50],
                   'lon': [40,50,60,70], }, 
                  index=['Location {}'.format(i) for i in range(1,5)])

cmap = plt.get_cmap('gist_rainbow_r')
df.plot(kind='scatter', x='lon', y='lat', s=df['Total']*50, c=df['Total'], cmap=cmap)

for idx, row in df.iterrows():
    x, y = row[['lon','lat']]
    plt.annotate(
        str(idx), 
        xy = (x, y), xytext = (-20, 20),
        textcoords = 'offset points', ha = 'right', va = 'bottom',
        bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
        arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))

plt.show()

产量

enter image description here


不要为每个数据点调用df.plotplt.scatter。随着数据点数量的增加,这样做会变得非常缓慢。相反,将必要的数据(经度和纬度)收集到DataFrame中,以便可以通过对df.plot一次调用绘制数据点:

longitudes, latitudes = [], []
for row_index, row in df.iterrows():
    x, y = db.getLocation(row_index)
    lat, lon = m(y, x)
    longitudes.append(lon)
    latitudes.append(lat)
    plt.annotate(
        str(row_index), 
        xy = (x, y), xytext = (-20, 20),
        textcoords = 'offset points', ha = 'right', va = 'bottom',
        bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
        arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))

df['lon'] = longitudes
df['lat'] = latitudes
cmap = plt.get_cmap('gist_rainbow_r')
ax = plt.gca()
df.plot(kind='scatter', x='lon', y='lat', s=df['Total']*50, c=df['Total'], 
        cmap=cmap, ax=ax)

非常好的详细回答!我只有一个问题。在df.iterrows()之外,我无法访问纬度和经度。我必须从数据库中获取这些数据(正如您可能从我的示例代码中看到的:x, y = db.getLocation(row_index))。我可以在循环的每次迭代中使用plt.scatter来获得相同的结果吗? - JNevens
在这种情况下,我该如何安排使用cmap的颜色? - JNevens
不要在循环的每次迭代中调用plt.scatter。这样做对于数百个点可能会使脚本变得非常缓慢。相反,将lonlat收集到列表或DataFrame中,以便可以通过一次调用df.plotplt.scatter绘制点。我已经编辑了上面的帖子,展示了其中一种方法。 - unutbu
我差不多让它工作了。问题是,它绘制了两个图形。一个是带注释的Basemap,另一个是DataFrame。 - JNevens
抱歉,我的错误。df.plot 默认创建一个新的轴,但是如果你将一个 axis 对象传递给它,那么就会使用该轴。因此 ax = plt.gca()(获取当前轴),并且 df.plot(..., ax=ax) 就是修复方法。(我已经在上面进行了更正。) - unutbu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接