如何在python(笔记本电脑)中使用高分辨率的卫星背景图像在地图上绘制(lat, lon, value)
数据?
我正在爬行整个互联网,但找不到任何有用的东西。 Folium不提供卫星瓷砖。 SimpleKML和googleearthplot似乎只对巨大的低分辨率地球数据有用。 EarthPy可以接受图像拼贴,但它们与NASA网站的链接仅提供> 0.1度的低分辨率图像。 Cartopy是matplotlib用户的新希望,但我找不到任何卫星图像拼贴的例子。
令人沮丧的是特别大,因为使用R
包装,例如:RGoogleMaps这项工作非常容易。
plotmap(lat, lon, col=palette(value), data=mydataframe, zoom = 17, maptype="satellite")
另一种选择是使用gmplot
。它基本上是围绕Google Maps javascript API的python包装器,允许您生成.html
文件,使用背景中的地图渲染您的绘图。
在这里,我用它来绘制一个卫星图像背景的随机游走(默认情况下不支持这种地图类型,但它非常简单,使它工作):
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地图一样进行交互。不幸的是,这意味着你不会得到一个漂亮的matplotlib
图形窗口或任何东西,所以为了生成一个图像文件,你需要自己截取屏幕截图或者破解一些东西来为你呈现HTML。
要记住的另一件事是你可能需要一个Google Maps API key,否则你会像我一样得到一个丑陋的黑暗水印地图:
此外,由于您想要将值描绘为颜色,您需要手动将它们转换为颜色字符串并使用gmap.scatter()
方法。如果您对此方法感兴趣,请告诉我,以便我可以尝试提供一些代码来做到这一点。
这是一个版本,支持将值编码为卫星图像上散点图中的颜色。为了达到这个效果,我使用matplotlib
的色彩图。您可以根据需要更改色彩映射,查看选项列表here。我还提供了一些代码来从文件apikey.txt
中读取API密钥,它允许每个研究人员使用他们自己的密钥而不更改代码(如果没有找到这样的文件,默认情况下没有像往常那样没有API密钥)。
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
色彩映射中很好地从蓝色阴影映射到红色:
通过注册Mapbox(mapbox.com)并使用他们提供的API密钥,您可以获得folium使用自定义tileset(他们的API_key=
和tile='Mapbox'
参数似乎对我不起作用)。
例如。这适用于我(但公共可用地图的分辨率根据位置而有所不同):
import folium
mapboxAccessToken = 'your api key from mapbox'
mapboxTilesetId = 'mapbox.satellite'
m = folium.Map(
location=[51.4826486,12.7034238],
zoom_start=16,
tiles='https://api.tiles.mapbox.com/v4/' + mapboxTilesetId + '/{z}/{x}/{y}.png?access_token=' + mapboxAccessToken,
attr='mapbox.com'
)
tooltip = 'Click me!'
folium.Marker([51.482696, 12.703918], popup='<i>Marker 1</i>', tooltip=tooltip).add_to(m)
folium.Marker([51.481696, 12.703818], popup='<b>Marker 2</b>', tooltip=tooltip).add_to(m)
m
我从来没有真正使用过Mapbox,但如果您碰巧有想要使用的图像,您甚至可以创建自己的tileset。
注意:我先在我的笔记本安装盘中运行了这个:
import sys
!{sys.executable} -m pip install folium
回应评论:
from bokeh.io import output_notebook, show
from bokeh.models import ColumnDataSource, GMapOptions, HoverTool
from bokeh.plotting import gmap, figure
output_notebook()
api_key = your_gmap_api_key
),所以也许你可以找到一个适合你的问题并自己包装的?使用Bokeh,根据我使用GMAP卫星磁贴可能是最简单的方法。
map_options = GMapOptions(lat=47.1839600, lng= 6.0014100, map_type="satellite", zoom=8, scale_control=True)
你的地图选项
hover=HoverTool(tooltips=[("(x,y)","($x,$y)")])
tools=[hover, 'lasso_select','tap']
添加一些工具以获得交互式地图
p = gmap(api_key, map_options, title="your_title", plot_height=600, plot_width=1000, tools=tools)
p.axis.visible = False
p.legend.click_policy='hide'
创建地图并对其进行自定义
your_source = ColumnDataSource(data=dict(lat=your_df.lat, lon=your_df.lon, size = your_df.value))
p.circle(x="lon",y="lat",size=size, fill_color="purple",legend = "your_legend", fill_alpha=0.2, line_alpha=0, source=your_source)
show(p)
添加您的数据
qazxswpoi