[英]Geotiff overlay position is slightly off on Holoviews/Bokeh tilemap
我有一个 Geotiff,显示在 map 的瓷砖上,但它稍微偏南。 例如,在这个屏幕截图中,图像的边缘应该是国家边界所在的位置,但它有点偏南:
这是代码的相关部分:
tiff_rio_500 = rioxarray.open_rasterio('/content/mw/mw_dist_to_light_at_all_from_light_mask_mw_cut_s3_500.tif')
dataarray_500 = tiff_rio_500[0]
dataarray_500_meters = dataarray_500.copy()
dataarray_500_meters['x'], dataarray_500_meters['y'] = ds.utils.lnglat_to_meters(dataarray_500.x, dataarray_500.y)
hv_dataset_500_meters = hv.Dataset(dataarray_500_meters, name='nightlights', vdims='cumulative_cost')
hv_tiles_osm_bokeh = hv.element.tiles.OSM().opts(width=1000, height=800)
hv_image_500_meters_bokeh = hv.Image(hv_dataset_500_meters, kdims=['x', 'y'], vdims=['cumulative_cost'], rtol=1).opts(cmap='inferno_r')
hv_combined_osm_500_meters_bokeh = hv_tiles_osm_bokeh * hv_image_500_meters_bokeh
hv_combined_osm_500_meters_bokeh
你可以在 google colab 上看到 live notebook。
现在,当人们不将 map 转换为 Web 墨卡托时,这不是常见的“一切都结束了”的问题。 它几乎是完美的,但事实并非如此。
Geotiff 是一个地球引擎出口。 这是它最初在 Earth Engine 中的样子( 参见实时代码):
如您所见,图像随处可见。
起初,我怀疑可能是导出出错了,或者 google map 瓦片集有些不同,但不是,如果我在 windows 笔记本电脑上的 QGis 应用程序中打开相同的导出 Tiff 并在同一个 OSM 瓦片图上查看它在 colab 笔记本中,它看起来不错:
好的,图像没有完美地遵循边界,但我知道为什么而且这无关(我过度简化了国家边界几何)。 关键是,它被投影到正确的位置。 因此,基于此,tiff 包含正确的信息,它可以显示在与 OSM tilemap 中的边界相同的位置,但在我的 Holoviews-Datashader-Bokeh 项目中,它仍然略有偏差。
知道为什么会这样吗?
我从一位开发人员那里得到了关于 Holoviz Discourse 的答案。 看到推荐的 function 几乎没有文档记录,我在这里复制它,以防有人寻找一种简单的方法来加载 geotiff 并添加到 Holoviews/Geoviews 中的 tilemap:
飞利浦
我不希望手动转换坐标工作得特别好。 虽然对于精确的坐标变换来说,它对权重的依赖性要大得多,但我建议使用GeoViews 。img = gv.util.load_tiff('/content/mw/mw_dist_to_light_at_all_from_light_mask_mw_cut_s3_500.tif') gv.tile_sources.OSM() * img.opts(cmap='inferno_r')
编辑:现在可能不想使用 Geoviews,因为它有一个非常重的依赖链,需要很大的耐心和运气才能正确设置它。 幸运的是 rioxarray(通过 rasterio)有一个重新投影的工具,只需 append ".rio.reproject('EPSG:3857')" 到第一行,然后您不必使用不用于此目的的 lnglat_to_meters。
所以修正后的代码变成:
tiff_rio_500 = rioxarray.open_rasterio('/content/mw/mw_dist_to_light_at_all_from_light_mask_mw_cut_s3_500.tif').rio.reproject('EPSG:3857')
hv_dataset_500_meters = hv.Dataset(tiff_rio_500[0], name='nightlights', vdims='cumulative_cost')
hv_tiles_osm_bokeh = hv.element.tiles.OSM().opts(width=1000, height=800)
hv_image_500_meters_bokeh = hv.Image(hv_dataset_500_meters, kdims=['x', 'y'], vdims=['cumulative_cost'], rtol=1).opts(cmap='inferno_r')
hv_combined_osm_500_meters_bokeh = hv_tiles_osm_bokeh * hv_image_500_meters_bokeh
hv_combined_osm_500_meters_bokeh
现在与 Geoviews 解决方案(据称自动处理所有内容)相比,该解决方案有一个缺点,即如果您使用 Hover 工具提示在鼠标 cursor 下显示值和坐标,坐标将显示在新投影的 Z2567A54EC9705EB7ACD2 系统中的 Z2567A54EC9705EB7ACD2数百万米,而不是预期的度数。 解决方案不在此答案的 scope 范围内,但我刚刚完成了一个详细的分步指南,其中也包含解决方案,一旦发布,我将在此处链接。 当然,如果您不使用 Hover Tooltip,上面的代码将非常适合您,无需任何修改。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.