Как сделать связанный выбор данных в HoloViews с помощью Datashader + Bokeh backend
Позвольте мне начать с дополнения разработчиков HoloViews, это удивительно. Есть только много частей, и немного трудно понять, как собрать их все вместе, чтобы сделать то, что я хочу:).
Я пытаюсь здесь выполнить связанное построение многомерных данных, то есть я хочу иметь несколько графиков, показывающих представления одних и тех же данных в различных измерениях. Затем я хочу использовать инструменты выбора Bokeh для выбора данных на одном из графиков и посмотреть, где они находятся на других. Но мне также нужно использовать Datashader для этого, потому что мои наборы данных большие.
Это то, что у меня есть (работает в блокноте Jupyter с Python 2)
import numpy as np
import pandas as pd
import holoviews as hv
import holoviews.operation.datashader as hvds
hv.notebook_extension('bokeh')
%opts Scatter [tools=['box_select', 'lasso_select']] (size=10 nonselection_color='red' color='blue') Layout [shared_axes=True shared_datasource=True]
# Create some data to plot
x1 = np.arange(0,10,1e-2)
x2 = np.arange(0,10,1e-2)
X1,X2 = np.meshgrid(x1,x2)
x1 = X1.flatten()
x2 = X2.flatten()
x3 = np.sin(x1) * np.cos(x2)
x4 = x1**2 + x2**2
# Pandas dataframe object from the data
print "Creating Pandas dataframe object"
df = pd.DataFrame.from_dict({"x1": x1, "x2": x2, "x3": x3, "x4": x4})
# Put the dataframe into a HoloViews table
dtab = hv.Table(df)
# Make some linked scatter plots using datashader
scat1 = dtab.to.scatter('x1', 'x2', [])
scat2 = dtab.to.scatter('x1', 'x3', [])
scat3 = dtab.to.scatter('x2', 'x4', [])
hvds.datashade(scat1) + hvds.datashade(scat2) + hvds.datashade(scat3)
Это производит следующее
что довольно фантастически просто. Однако это не совсем то, что я хочу. Изменения диапазонов данных и панорамирования связаны, что очень круто, однако данные за пределами диапазона одного графика все же могут быть построены на других. Я хотел бы, чтобы эти данные исчезли со всех графиков, чтобы я мог видеть только те данные, которые попадают во все просмотренные диапазоны данных, чтобы можно было динамически выбирать некоторый гиперкуб данных для выделения в многомерном пространстве.
Кроме того, было бы хорошо, чтобы инструменты выделения Bokeh работали так же, чтобы, например, я мог выбрать некоторые точки на одном графике и показать их все красным или что-то на других графиках. Я даже не получаю инструменты выделения, хотя и спрашиваю 'box_select' и 'lasso_select'. Я, вероятно, неправильно их просил, хотя мне не совсем понятно, как HoloViews передает параметры.
2 ответа
Вы можете использовать HoloViews Streams, чтобы выбрать данные для отображения, используя только видимые в данный момент точки. Пример можно найти по адресу: https://anaconda.org/petrenko/linking_datashaders
Исходя из ответа Джеймса ( /questions/5002856/kak-sdelat-svyazannyij-vyibor-dannyih-v-holoviews-s-pomoschyu-datashader-bokeh-backend/5002862#5002862), я расширил пример в вопросе следующим образом. Он принимает один график в качестве "основного" источника управления и отображает только те данные, которые появляются в пределах диапазонов данных этого графика, на несколько "подчиненных" графиков. Было бы неплохо иметь двусторонние отношения, но это довольно круто.
import numpy as np
import pandas as pd
import holoviews as hv
import holoviews.operation.datashader as hvds
hv.notebook_extension('bokeh')
%opts Layout [shared_axes=False shared_datasource=True]
# Create some data to plot
x1 = np.arange(0,10,1e-2)
x2 = np.arange(0,10,1e-2)
X1,X2 = np.meshgrid(x1,x2)
x1 = X1.flatten()
x2 = X2.flatten()
x3 = np.sin(x1) * np.cos(x2)
x4 = x1**2 + x2**2
# Pandas dataframe object from the data
print "Creating Pandas dataframe object"
df = pd.DataFrame.from_dict({"x1": x1, "x2": x2, "x3": x3, "x4": x4})
# Make some linked scatter plots using datashader
x1_x2 = hv.Points(df[['x1', 'x2']])
#x1_x3 = hv.Points(df[['x1', 'x3']])
#x2_x4 = hv.Points(df[['x2', 'x4']])
from holoviews import streams
maindata=x1_x2
mainx='x1'
mainy='x2'
def create_dynamic_map(xvar,yvar):
def link_function(x_range, y_range):
x_min = x_range[0]; x_max = x_range[1]
y_min = y_range[0]; y_max = y_range[1]
pts = hv.Points(df[ (getattr(df,mainx) > x_min) & (getattr(df,mainx) < x_max)
& (getattr(df,mainy) > y_min) & (getattr(df,mainy) < y_max)
][[xvar, yvar]])
return pts
dmap = hv.DynamicMap(link_function,
streams=[hv.streams.RangeXY(x_range=(-100,100),
y_range=(-100,100),
source=maindata)],
kdims=[])
return dmap
x1_x3 = create_dynamic_map('x1','x3')
x2_x4 = create_dynamic_map('x2','x4')
hvds.datashade(x1_x2) + hvds.datashade(x1_x3) + hvds.datashade(x2_x4)