Как изменить размер бинов / пикселей при масштабировании - PullRequest
0 голосов
/ 29 февраля 2020

В настоящее время я пытаюсь спроецировать набор данных (Berlin publi c транспортных точек) на плитки с помощью datashader и bokeh. В определенной степени это работало хорошо, в то время как остаются три проблемы:

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

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

(далек от совершенства) написанный код:

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')

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

Bokeh plot of the dataset (not zoomed) Bokeh plot of the dataset (zoomed)

1 Ответ

1 голос
/ 01 марта 2020
  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 исчезла, поскольку плитки карты были объединены. Как вернуть его обратно?

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

...