Я строю 550 000 000 широт и долгот, используя datashader
.Но для того, чтобы это было полезно, мне нужно наложить плитки и полигоны карты, используя geoviews
.Проблема заключается в том, что 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) Просто набор данных
Просто использовать datashader без holoviews или geo очень быстро - вывод обрабатывается за 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())
Процессорное время: пользовательский 968 мс, системный: 29,9 мс, общее время: 998 мс Время настенного режима: 506 мс
tf.shade(agg)
(2) datashader
в holoviews
без geoviews
проекции
# 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)
ЦП: пользователь 3,32 мс, sys: 131 мкс, всего: 3,45 мс Время стены: 3,47 мс
shader
(3) datashader
inholoviews
с geoviews
плитками, полигонами и проекцией
Вот суть вопроса - я хочу совместить слой с даташерами с некоторыми плитками карты и геопространственными полигонами.Это приводит к значительному замедлению, что для размера данных, с которыми я имею дело, делает избыточной интерактивную визуализацию.(Всего 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)
Время ЦП: пользовательский 11,8 с, системный: 3,16 с, всего: 15 с Время нахождения на стене: 12,5 с
shader * map_tiles * polys