Python 地理视图&x2B;投影点时,Datashader速度较慢
我正在使用Python 地理视图&x2B;投影点时,Datashader速度较慢,python,holoviews,datashader,geoviews,Python,Holoviews,Datashader,Geoviews,我正在使用datashader绘制550000000个纬度和经度。但是,为了使其有用,我需要使用geoviews覆盖贴图平铺和多边形。问题是geoviews.points()和相关的投影会导致大幅减速,这使得holoview+bokeh绘图的交互特性变得多余 下面有一个可复制的示例,但简而言之,我正在尝试使geoviews实现(3)足够快,以交互方式工作 首先设置一些数据 例如,将数据大小缩小10 uk_bounding_box = (-14.02,2.09,49.67,61.06) n = i
datashader
绘制550000000个纬度和经度。但是,为了使其有用,我需要使用geoviews
覆盖贴图平铺和多边形。问题是geoviews.points()
和相关的投影会导致大幅减速,这使得holoview
+bokeh
绘图的交互特性变得多余
下面有一个可复制的示例,但简而言之,我正在尝试使geoviews实现(3)足够快,以交互方式工作
首先设置一些数据
例如,将数据大小缩小10
uk_bounding_box = (-14.02,2.09,49.67,61.06)
n = int(550000000 / 10)
# Generate some fake data of the same size
df = dd.from_pandas(
pd.DataFrame.from_dict({
'longitude': np.random.normal(
np.mean(uk_bounding_box[0:2]),
np.diff(uk_bounding_box[0:2]) / 5, n
),
'latitude': np.random.normal(
np.mean(uk_bounding_box[2:4]),
np.diff(uk_bounding_box[2:4]) / 5, n
)
}), npartitions=8
)
# Persist data in memory so reading wont slow down datashader
df = df.persist()
(1) 只是数据阴影
仅使用不带HoloView或geo的datashader是非常快速的-输出在4秒内渲染,包括聚合,因此如果交互,重新渲染将更快
# Set some plotting params
bounds = dict(x_range = uk_bounding_box[0:2],
y_range = uk_bounding_box[2:4])
plot_width = 400
plot_height = 300
纯datashader版本的时间:
%%time
cvs = ds.Canvas(plot_width=plot_width, plot_height=plot_height, **bounds)
agg = cvs.points(df, 'longitude', 'latitude', ds.count())
CPU时间:用户968毫秒,系统29.9毫秒,总计998毫秒
壁时间:506毫秒
tf.shade(agg)
(2) datashader
在holoviews
中,无geoviews
投影
没有任何投影,这与使用纯datashader
%%time
points = hv.Points(df, ['longitude', 'latitude']).redim.range(
x=bounds['x_range'], y=bounds['y_range'])
shader = datashade(points, precompute=True ,**sizes).options(**opts)
CPU时间:用户3.32毫秒,系统131微秒,总计3.45毫秒
壁时间:3.47毫秒
shader
(3) datashader
在holoviews
中使用geoviews
瓷砖、多边形和投影
这里是问题的症结所在-我想将datashader层与一些地图分幅和地理空间多边形对齐。这导致了一个巨大的减速,对于我正在处理的数据的大小来说,这使得交互式可视化变得多余。(渲染的总等待时间为12分钟)
我确信这与投影点相关的开销有关-有没有办法避免这种情况或任何其他解决方法,如预计算投影
# Grab an example shape file to work with
ne_path = gpd.datasets.get_path('naturalearth_lowres')
example_shapes_df = gpd.read_file(ne_path)
uk_shape = example_shapes_df[example_shapes_df.name.str.contains('United K')]
# Grab maptiles
map_tiles = gv.tile_sources.ESRI
# In actual workflow I need to add some polygons
polys = gv.Polygons(uk_shape)
如上所述,添加了gv.points()
和投影
%%time
points = gv.Points(df, ['longitude', 'latitude']).redim.range(
x=bounds['x_range'], y=bounds['y_range'])
projected = gv.operation.project_points(points)
shader = datashade(projected, precompute=True ,**sizes).options(**opts)
CPU时间:用户11.8秒,系统3.16秒,总计15秒
壁时间:12.5秒
shader * map_tiles * polys
根据@philippjfr的建议,解决方案是将坐标投影到适当的坐标系中,并使用上述方法2或3进行渲染 大概是这样的:
import cartopy
def platcaree_to_mercator_vectorised(x, y):
'''Use cartopy to convert Platecarree coords to Mercator.'''
return(cartopy.crs.GOOGLE_MERCATOR.transform_points(
cartopy.crs.PlateCarree(), x, y))
def platcaree_for_map_partitions(pddf):
'''Wrapper to apply mercator conversion and convert back to dataframe for Dask.'''
as_arrays = platcaree_to_mercator_vectorised(pddf.longitude.values,pddf.latitude.values)
as_df = pd.DataFrame.from_records(as_arrays[:, :2], columns=['longitude', 'latitude'])
return(as_df)
# Project the points
df_projected = df.map_partitions(platcaree_for_map_partitions,
meta={'longitude': 'f8', 'latitude': 'f8'})
from dask.diagnostics import ProgressBar
with ProgressBar():
df_projected.to_parquet('abb_projected.parquet', compression='SNAPPY')
然后将此投影数据集与方法2或3一起使用,详细说明见上文 你能澄清一下时间安排吗?您说需要12分钟,但%%time输出表示12秒,在本地运行示例时,投影大约需要30秒,渲染大约需要1.5秒,缩放更新大约需要300毫秒。Hi@philippjfr-在实际代码中,数据是示例大小的10倍
n=int(550000000/10)
我在这里对其进行了缩放,因此运行该示例不需要太长时间,但当我使用完整的550000000坐标时,最终的绘图需要12分钟。这是实际数据的每次时间,与上面的代码相同,但对于550000,00点:1)CPU时间:用户8.4秒,系统:16.1秒,总计:24.4秒壁时间:4.38秒
2)CPU时间:用户3.9毫秒,系统476微秒,总计:4.38毫秒壁时间:4.35毫秒
3)CPU时间:用户3分钟24秒,系统6分钟27秒,总计:9分钟51s墙时间:10分钟31s
查看剖面图,似乎投影占用了大部分时间:``ncalls tottime percall cumtime percall filename:lineno(函数)1268.726 268.726 268.726 268.726{cartopy.\u crs.crs'对象的方法“变换点”}191.124 191.124 625.980 625.980 projection.py:188(_process_element)8127.947 15.993 127.947 15.993{内置方法numpy.core.multiarray.concatenate}1 34.910 34.910 34.910 34.910 34.910 projection.py:195()1 2.001 627.981 627.981维。py:712(map)``谢谢,我应该仔细阅读。我们计划最终将投影代码与dask并行,但目前我只能建议您投影一次点,然后将投影点保存为拼花地板文件;GeoViews不会不必要地重新投影数据。因此,在投影之后,您不必避免地理视图,您只是不需要它。
shader * map_tiles * polys
import cartopy
def platcaree_to_mercator_vectorised(x, y):
'''Use cartopy to convert Platecarree coords to Mercator.'''
return(cartopy.crs.GOOGLE_MERCATOR.transform_points(
cartopy.crs.PlateCarree(), x, y))
def platcaree_for_map_partitions(pddf):
'''Wrapper to apply mercator conversion and convert back to dataframe for Dask.'''
as_arrays = platcaree_to_mercator_vectorised(pddf.longitude.values,pddf.latitude.values)
as_df = pd.DataFrame.from_records(as_arrays[:, :2], columns=['longitude', 'latitude'])
return(as_df)
# Project the points
df_projected = df.map_partitions(platcaree_for_map_partitions,
meta={'longitude': 'f8', 'latitude': 'f8'})
from dask.diagnostics import ProgressBar
with ProgressBar():
df_projected.to_parquet('abb_projected.parquet', compression='SNAPPY')