python - Geoviews + Datashader 投影点时速度很慢

标签 python holoviews datashader geoviews

我正在使用 datashader 绘制 550,000,000 个纬度和经度。但是,为了使其有用,我需要使用 geoviews 覆盖 map 图 block 和多边形。问题在于,geoviews.points() 和相关的投影会导致速度大幅下降,从而使 Holoview + Bokeh 图的交互性质变得多余。

下面有一个可重现的示例,但是,简而言之 - 我正在尝试使 geoviews 实现 (3) 足够快以交互工作。

首先设置一些数据

import numpy as np
import pandas as pd
import dask.dataframe as dd
import datashader as ds
import datashader.transfer_functions as tf
import holoviews as hv 
from holoviews.operation.datashader import datashade
import geopandas as gpd
import geoviews as gv

例如,将数据大小缩小 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) 只是数据着色器

仅使用不带 Holoviews 或 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)

just data shader

(2) 没有 geoviews 投影的 holoviews 中的 datashader

# Set some params
sizes = dict(width=plot_width, height=plot_height)
opts = dict(bgcolor="black", **sizes)

hv.extension('bokeh')

hv.util.opts('Image Curve RGB Polygons [width=400 height=300 shared_axes=False] {+axiswise} ')

没有任何投影,这相当于使用纯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 ms,系统:131 µs,总计:3.45 ms 挂起时间:3.47 毫秒

shader

holoviews render

(3) holoviews 中的 datashader 以及 geoviews 切片、多边形和投影

这是问题的关键 - 我想将数据着色器层与一些 map 图 block 和地理空间多边形对齐。这会导致速度大幅下降,对于我正在处理的数据大小而言,使得交互式可视化变得多余。 (渲染总共等待 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

geoviews render

最佳答案

按照@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 一起使用,详见相关问题。

关于python - Geoviews + Datashader 投影点时速度很慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53544693/

相关文章:

python - 如何使用 datashader 为图表的节点着色?

python - 在python中将图像转换为矩阵

python - Holoviz/Param/Panel : is it possible to change, 隐藏或删除保存参数化类参数的参数面板的标题?

python - Pandas 数据框列中的 "Sandwich"值?

python - 如何访问通过 Holoviews 中的流选择的值?

python - 如何使用 Bokeh 后端控制全息 View 中的(事件)工具

python - 用于使用 Datashader/Holoviews/Bokeh 循环子图

python - hvplot - 如何按分类变量对点数据着色并与 `ds.count_cat(.)` 聚合

使用 matplotlib/basemap 进行 Python 插值

python - python2.7和python 3.4中的ord函数有什么不同?