Как изменить размер бинов / пикселей при масштабировании

В настоящее время я пытаюсь спроецировать набор данных (места общественного транспорта Берлина) на карты с помощью даташейдера и боке. В определенной степени это сработало хорошо, но остаются три проблемы:

  1. при увеличении данных пиксели остаются довольно большими и не меняются местами - как это сделать?
  2. как сделать проецируемые данные полупрозрачными, чтобы по-прежнему видеть карту ниже?
  3. функция «сохранить» на панели инструментов боке исчезла, так как фрагменты карты были объединены. Как вернуть?

Спасибо за любой вклад!

написанный (далеко не идеальный) код:

import numpy as np
import pandas as pd
import geopandas as gp
import datashader as ds
import datashader.transfer_functions as tf
from datashader.utils import export_image
from datashader.utils import lnglat_to_meters as webm
from datashader.colors import Hot
import dask.dataframe as dd
import multiprocessing as mp
from functools import partial
from IPython.core.display import HTML, display
import matplotlib.pyplot as plt
import holoviews as hv
from holoviews.operation.datashader import datashade, dynspread
hv.extension("bokeh", "matplotlib")
from bokeh.io import output_file, output_notebook, show
from bokeh.plotting import figure, show
from holoviews import dim, opts
import geoviews as gv
from colorcet import palette, fire

#get official data of bus/subway stops in Berlin
# -> https://www.vbb.de/media/download/2035
#read data
df = pd.read_csv('UMBW.CSV', engine= 'python', sep=';', usecols=['Y-Koordinate', 'X-Koordinate'])

##some formatting
##replace comma by point
df = df.apply(lambda x: x.str.replace(',','.'))
#delete rows witn NaN -> pandas.DataFrame.dropna
df = df.dropna()
#entries were objects - need to convert to floats
df['X-Koordinate']=pd.to_numeric(df['X-Koordinate'])
df['Y-Koordinate']=pd.to_numeric(df['Y-Koordinate'])

# Project longitude and latitude onto web mercator plane.
df.loc[:, 'easting'], df.loc[:, 'northing'] = webm(df['X-Koordinate'],df['Y-Koordinate'])

# Getting range/box of latitude and longitude for plotting later.
# drop the points lying on the border
y_range_min = df['Y-Koordinate'].quantile(0.01)
y_range_max = df['Y-Koordinate'].quantile(0.99)
x_range_min = df['X-Koordinate'].quantile(0.01)
x_range_max = df['X-Koordinate'].quantile(0.99)

#cornerspots for canvas
sw = webm(x_range_min,y_range_min)#southwest
ne = webm(x_range_max,y_range_max)#northeast
SF = zip(sw, ne)

dask_df = dd.from_pandas(df, npartitions=mp.cpu_count())
dask_df = dask_df.compute()

display(HTML("<style>.container { width:100% !important; }</style>"))

plot_width = int(3600)
plot_height = int(3600)
cvs = ds.Canvas(plot_width, plot_height, *SF)
agg = cvs.points(dask_df, 'easting', 'northing')

#dynamic map tiles -> https://wiki.openstreetmap.org/wiki/Tile_servers
#url="http://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{Z}/{Y}/{X}.png"
url="https://a.tile.openstreetmap.org/{Z}/{X}/{Y}.png"
geomap = gv.WMTS(url)

#manipulate pixelsize for zoom
dynspread.max_px=1
dynspread.threshold=0.1

points = hv.Points(gv.Dataset(dask_df, kdims=['easting', 'northing']))
bvg_stops = dynspread(datashade(points, cmap=Hot).opts(height=640,width=640))
fig = geomap * bvg_stops
hv.save(fig, 'berlin.html', backend='bokeh')

Пример вывода начального участка боке и увеличенной версии (вокруг города Котбус).

График боке набора данных (без увеличения)  График боке набора данных (увеличенный)


person Nikolaij    schedule 29.02.2020    source источник


Ответы (1)


  1. при увеличении данных пиксели остаются довольно большими и не меняются местами - как это сделать?

    Datashader - это программа Python, которая создает массив растеризованных значений при заданной структуре данных. Здесь он отображает ваши данные в соответствии с запросом, а затем вы сохраняете их вывод в файл HTML с помощью hv.save. Как только вы это сделаете, у вас будет фигура, которая никогда не обновится. Вы увеличите масштаб HTML-страницы, в результате чего код JavaScript браузера будет запрашивать обновление у Python, но Python не работает и не может ответить на запрос обновленного рисунка. Если вы хотите экспортировать масштабируемое изображение в HTML, вам нужно либо указать гораздо более высокое начальное разрешение, чем что-то вроде datashade(..., dynamic=False, height=4000, width=4000) (что даст большой размер файла и может не выглядеть хорошо изначально, но допускает некоторую степень масштабирования), или же сгенерируйте целый набор плиток данных с множеством различных разрешений (поддерживаемых Datashader, но еще недостаточно хорошо документированных), либо (для полной мощности) используйте сервер Bokeh, чтобы предоставить процесс Python для сопровождения кода HTML / JavaScript. То есть, либо сначала сгенерируйте немного больше данных, либо заранее сгенерируйте все комбинации данных, либо предоставьте сервер, который может их регенерировать по запросу. Без одного из этих подходов не следует ожидать, что будут доступны какие-либо данные помимо первоначального рендеринга.

  2. как сделать проецируемые данные полупрозрачными, чтобы по-прежнему видеть карту ниже?

    bvg_stops.opts(alpha=0.5). Вы также можете рассмотреть возможность использования Panel.pyviz.org для добавления некоторых виджетов для обеспечения прозрачности карты и данных, чтобы вы могли включать и выключать их в интерактивном режиме; см. примеры на examples.pyviz.org.

  3. функция сохранения панели инструментов боке исчезла, так как фрагменты карты были объединены. Как вернуть?

    К сожалению, это ограничение вызвано моделью безопасности браузера и не может быть отменено Bokeh или другими инструментами. Фрагменты карты поступают с отдельного сервера, и браузеры отключают экспорт такого контента из разных источников, чтобы избежать определенных проблем с безопасностью (Невозможно сохранить график боке с панелью из примера PyViz).

person James A. Bednar    schedule 01.03.2020
comment
Большое спасибо за подробные ответы. Мне определенно придется покопаться в серверах Bokeh. Кстати, Datashader - потрясающая графическая система! - person Nikolaij; 02.03.2020