python - 在卫星 map 上绘制数据

标签 python pandas google-maps plot maps

如何在 python(笔记本)中使用高分辨率的卫星背景图像在 map 上绘制 (lat, lon, value) 数据?

我正在搜索整个互联网,但找不到任何有用的东西。 Folium不提供卫星图 block 。 SimpleKMLgoogleearthplot似乎只对巨大的低分辨率地球数据有用。 EarthPy可以接受图像 block ,但它们到 NASA 网站的链接仅提供 >0.1 度的低分辨率图像。 Cartopy是 matplotlib 用户的新希望,但我找不到卫星图像 block 的任何示例。

挫败感特别大,因为使用 R,使用 RGoogleMaps 可以非常轻松地完成这项工作。包,例如:

plotmap(lat, lon, col=palette(value), data=mydataframe, zoom = 17, maptype="satellite")

我们如何在 Python 中做到这一点? plot on satellite maps

最佳答案

另一种选择是使用 gmplot .它基本上是一个围绕 Google Maps javascript API 的 python 包装器,允许您生成 .html 文件,在后台使用 map 渲染您的绘图。

在这里我用它来绘制卫星图像背景下的随机游走(默认情况下不支持这种 map 类型,但让它工作非常简单):

from gmplot import GoogleMapPlotter
from random import random

# We subclass this just to change the map type
class CustomGoogleMapPlotter(GoogleMapPlotter):
    def __init__(self, center_lat, center_lng, zoom, apikey='',
                 map_type='satellite'):
        super().__init__(center_lat, center_lng, zoom, apikey)

        self.map_type = map_type
        assert(self.map_type in ['roadmap', 'satellite', 'hybrid', 'terrain'])

    def write_map(self,  f):
        f.write('\t\tvar centerlatlng = new google.maps.LatLng(%f, %f);\n' %
                (self.center[0], self.center[1]))
        f.write('\t\tvar myOptions = {\n')
        f.write('\t\t\tzoom: %d,\n' % (self.zoom))
        f.write('\t\t\tcenter: centerlatlng,\n')

        # This is the only line we change
        f.write('\t\t\tmapTypeId: \'{}\'\n'.format(self.map_type))


        f.write('\t\t};\n')
        f.write(
            '\t\tvar map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);\n')
        f.write('\n')

initial_zoom = 16
num_pts = 40

lats = [37.428]
lons = [-122.145]
for pt in range(num_pts):
    lats.append(lats[-1] + (random() - 0.5)/100)
    lons.append(lons[-1] + random()/100)
gmap = CustomGoogleMapPlotter(lats[0], lons[0], initial_zoom,
                              map_type='satellite')
gmap.plot(lats, lons, 'cornflowerblue', edge_width=10)

gmap.draw("mymap.html")

您可以在浏览器中打开生成的 .html 文件,并像与 Google map 一样进行交互。 不幸的是,这意味着你不会得到一个漂亮的 matplotlib 图形窗口或任何东西,所以为了生成一个图像文件,你需要自己截屏或者破解一些东西来渲染 HTML你。

要记住的另一件事是您可能需要一个 Google Maps API key ,否则你会像我一样得到一张丑陋的深色水印 map :

Random walk map

此外,由于您希望将值描述为颜色,因此您需要手动将这些值转换为颜色字符串并使用 gmap.scatter() 方法。如果您对这种方法感兴趣,请告诉我,这样我就可以尝试编写一些代码来实现这一点。

更新

这是一个支持将值编码为卫星图像散点图中颜色的版本。为了实现这种效果,我使用了 matplotlib 的颜色图。如果需要,您可以更改颜色图,请参阅选项列表 here .我还包含了一些代码以从文件 apikey.txt 中读取 API key ,这允许每个研究人员使用他们自己的个人 key 而不更改代码(如果没有找到这样的文件,默认为没有像往常一样的 API key )。

import matplotlib.pyplot as plt
from matplotlib.colors import Normalize
from matplotlib.cm import ScalarMappable
from gmplot import GoogleMapPlotter
from random import random


class CustomGoogleMapPlotter(GoogleMapPlotter):
    def __init__(self, center_lat, center_lng, zoom, apikey='',
                 map_type='satellite'):
        if apikey == '':
            try:
                with open('apikey.txt', 'r') as apifile:
                    apikey = apifile.readline()
            except FileNotFoundError:
                pass
        super().__init__(center_lat, center_lng, zoom, apikey)

        self.map_type = map_type
        assert(self.map_type in ['roadmap', 'satellite', 'hybrid', 'terrain'])

    def write_map(self,  f):
        f.write('\t\tvar centerlatlng = new google.maps.LatLng(%f, %f);\n' %
                (self.center[0], self.center[1]))
        f.write('\t\tvar myOptions = {\n')
        f.write('\t\t\tzoom: %d,\n' % (self.zoom))
        f.write('\t\t\tcenter: centerlatlng,\n')

        # Change this line to allow different map types
        f.write('\t\t\tmapTypeId: \'{}\'\n'.format(self.map_type))

        f.write('\t\t};\n')
        f.write(
            '\t\tvar map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);\n')
        f.write('\n')

    def color_scatter(self, lats, lngs, values=None, colormap='coolwarm',
                      size=None, marker=False, s=None, **kwargs):
        def rgb2hex(rgb):
            """ Convert RGBA or RGB to #RRGGBB """
            rgb = list(rgb[0:3]) # remove alpha if present
            rgb = [int(c * 255) for c in rgb]
            hexcolor = '#%02x%02x%02x' % tuple(rgb)
            return hexcolor

        if values is None:
            colors = [None for _ in lats]
        else:
            cmap = plt.get_cmap(colormap)
            norm = Normalize(vmin=min(values), vmax=max(values))
            scalar_map = ScalarMappable(norm=norm, cmap=cmap)
            colors = [rgb2hex(scalar_map.to_rgba(value)) for value in values]
        for lat, lon, c in zip(lats, lngs, colors):
            self.scatter(lats=[lat], lngs=[lon], c=c, size=size, marker=marker,
                         s=s, **kwargs)


initial_zoom = 12
num_pts = 40

lats = [37.428]
lons = [-122.145]
values = [random() * 20]
for pt in range(num_pts):
    lats.append(lats[-1] + (random() - 0.5)/100)
    lons.append(lons[-1] + random()/100)
    values.append(values[-1] + random())
gmap = CustomGoogleMapPlotter(lats[0], lons[0], initial_zoom,
                              map_type='satellite')
gmap.color_scatter(lats, lons, values, colormap='coolwarm')

gmap.draw("mymap.html")

作为示例,我使用了一系列单调递增的值,这些值在 coolwarm 颜色图中很好地从蓝色阴影映射到红色:

New map example with colors

关于python - 在卫星 map 上绘制数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53873673/

相关文章:

python - Scipy:稀疏矩阵的维数错误?

python - 如何用彩色分割和 alpha channel 绘制图片?

python - Python 的 asyncio lock.acquire 是否维持秩序?

python - 通过字符串调用外部模块中的Python函数

python - 获取 pandas 数据框中的标题行

javascript - 可扩展的谷歌地图覆盖

javascript - Google map 看起来在 div 内移动了

python - 将涉及 Pandas 中另一个数据框的用户定义函数应用于整个数据框

python - Pandas 时间序列的线性回归

java - 选择地点或尝试返回时,Android 地点选择器显示空白屏幕