如何解决使用值列
我有一些GPS数据,每个点都分配了一个值(就像空气质量一样)。我可以绘制这些点(例如,用大叶草),然后将值映射到圆的大小,如下所示:
import pandas,numpy,folium
lat = numpy.random.uniform(45,45.01,250)
lon = numpy.random.uniform(3,3.02,250)
value = numpy.random.uniform(0,50,250)
df = pandas.DataFrame({'lat': lat,'lon': lon,'value': value})
mymap = folium.Map(location = [lat.mean(),lon.mean()],tiles="OpenStreetMap",zoom_start=14)
for elt in list(zip(df.lat,df.lon,df.value)):
folium.Circle(elt[:2],color="blue",radius=elt[2]).add_to(mymap)
mymap.save('mymap.html')
我想处理这些数据,对其进行插值并创建一个shapefile作为输出,其中插值的多边形包含平均值,并显示高和低值区域(右侧的 fake 图片)。当然,多边形的极限将根据插值自动生成。
我该如何实现?因为我已经尝试在大叶草中使用HeatMap工具,但是它的设计是为了插值点的密度,而不是与每个点关联的值! 我希望它不会太复杂。谢谢, 注意:我使用叶草,但我对其他python库也没问题。
解决方法
我们可以将这些值作为权重馈送到大叶中的HeatMap(请参阅文档中的data
参数)。
这是一个例子。我将方框下半部分的值除以5,以证明尽管数据点的密度相对均匀,但热图在图片的上半部分显然显示出更高的幅度:
import pandas as pd
import numpy as np
import folium
from folium.plugins import HeatMap
import matplotlib as mpl
# parameters
n = 250 # number of points
lat0 = 40.7 # coordinates will be generated uniformly with
lon0 = -73.9 # lat0 - eps <= lat < lat0 + eps
eps = 0.1 # lon0 - eps <= lon < lon0 + eps
v_min,v_max = 0,100 # min,max values
# generating values
lat = np.random.uniform(lat0 - eps,lat0 + eps,n)
lon = np.random.uniform(lon0 - eps,lon0 + eps,n)
value = numpy.random.uniform(v_min,v_max,n)
df = pandas.DataFrame({'lat': lat,'lon': lon,'value': value})
# to demonstrate the effect of weights on the heatmap,# we'll divide values below the center of the box by K = 5
K = 5
df.loc[df['lat'] < lat0,'value'] /= K
# plotting the map,both the points themselves and the heatmap
m = folium.Map(location = [lat0,lon0],tiles="OpenStreetMap",zoom_start=11,width=400,height=400)
for elt in list(zip(df.lat,df.lon,df.value)):
folium.Circle(elt[:2],color="white",radius=elt[2]).add_to(m)
# df.values used here is a (250,3) numpy.ndarray
# with (lat,lon,weight) for each data point
HeatMap(data=df.values,min_opacity=0.1).add_to(m)
m
输出:
更新:
这是一种略有不同的方法,不使用内置的HeatMaps(鉴于@agenis提到的https://github.com/python-visualization/folium/issues/1271,这可能是一个更好的选择)。
我们首先将数据转换为正方形网格,其中每个正方形的值是该单元格内原始数据点值的平均值(因此,它不取决于该单元格内点的数量,仅取决于它们的值)。
然后,我们可以通过在地图上绘制GeoJson多边形来可视化这些正方形。这是一个示例:
# define the size of the square
step = 0.02
# calculate values for the grid
x = df.copy()
x['lat'] = np.floor(x['lat'] / step) * step
x['lon'] = np.floor(x['lon'] / step) * step
x = x.groupby(['lat','lon'])['value'].mean()
x /= x.max()
x = x.reset_index()
# geo_json returns a single square
def geo_json(lat,value,step):
cmap = mpl.cm.RdBu
return {
"type": "FeatureCollection","features": [
{
"type": "Feature","properties": {
'color': 'white','weight': 1,'fillColor': mpl.colors.to_hex(cmap(value)),'fillOpacity': 0.5,},"geometry": {
"type": "Polygon","coordinates": [[
[lon,lat],[lon,lat + step],[lon + step,]]}}]}
# generating a map...
m = folium.Map(location=[lat0,height=400)
# ...with squares...
for _,xi in x.iterrows():
folium.GeoJson(geo_json(xi['lat'],xi['lon'],xi['value'],step),lambda x: x['properties']).add_to(m)
# ...and the original points
for elt in list(zip(df.lat,radius=elt[2]).add_to(m)
m
输出:
更新(2):
以下是使用griddata
在网格上进行插值的版本:
import pandas as pd
import numpy as np
import folium
from scipy.interpolate import griddata
# parameters
n = 250 # number of points
lat0 = 40.7
lon0 = -73.9
eps = 0.1
v_min,max values
# generating values
lat = np.random.normal(lat0,eps,n)
lon = np.random.normal(lon0,n)
# set up the grid
step = 0.02
xi,yi = np.meshgrid(
np.arange(lat.min() - step/2,lat.max() + step/2,np.arange(lon.min() - step/2,lon.max() + step/2,)
# interpolate and normalize values
zi = griddata((lat,lon),(xi,yi),method='linear')
zi /= np.nanmax(zi)
g = np.stack([
xi.flatten(),yi.flatten(),zi.flatten(),],axis=1)
# geo_json returns a single square
def geo_json(lat,"coordinates": [[
[lon - step/2,lat - step/2],[lon - step/2,lat + step/2],[lon + step/2,zoom_start=9,height=400)
# ...with squares...
for gi in g:
if ~np.isnan(gi[2]):
folium.GeoJson(geo_json(gi[0],gi[1],gi[2],lambda x: x['properties']).add_to(m)
# ...and the original points
for elt in list(zip(lat,value)):
folium.Circle(elt[:2],color='white',radius=elt[2]).add_to(m)
m
输出:
,在我看来,您需要过滤数据,以便根据给定类别将其分为几组。使用这些点集,您便应该能够生成凸包。似乎有一些方法可以做到此目的-请参见此处的一些示例: Convex hull area in Python?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。