Как сделать выбор связанных данных в HoloViews с бэкэндом Datashader + Bokeh

Позвольте мне начать с дополнения разработчиков HoloViews, это довольно потрясающая вещь. Здесь просто много частей, и немного сложно понять, как собрать их все вместе, чтобы делать то, что я хочу :).

Я пытаюсь сделать здесь построение связанных многомерных данных, т.е. я хочу иметь несколько графиков, показывающих представления одних и тех же данных по различным измерениям. Затем я хочу использовать инструменты выбора боке, чтобы выбрать данные на одном из графиков и посмотреть, где они находятся на других. Но для этого мне также нужно использовать 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)

Это дает следующие

введите здесь описание изображения

что довольно просто фантастически. Однако это не совсем то, что я хочу. Изменения диапазонов данных и панорамирование связаны, что очень круто, однако данные за пределами диапазона одного графика все еще могут быть нанесены на другие. Я хотел бы, чтобы эти данные исчезли со всех графиков, чтобы я видел только те данные, которые попадают во все просматриваемые диапазоны данных, чтобы можно было динамически выбирать некоторый гиперкуб данных для выделения в многомерном пространстве.

Кроме того, было бы хорошо, если бы инструменты выбора боке работали одинаково, чтобы, например, я мог выбрать несколько точек на одном графике, и все они отображались красным цветом или чем-то еще на других графиках. Я даже не получаю инструментов выбора, несмотря на то, что прошу box_select и lasso_select. Вероятно, я спросил их неправильно, мне не совсем понятно, как HoloViews передает параметры.


person Ben Farmer    schedule 31.05.2017    source источник


Ответы (2)


Вы можете использовать потоки HoloViews, чтобы выбрать данные для отображения, используя только видимые в данный момент точки. Пример можно найти по адресу: https://anaconda.org/petrenko/linking_datashaders

person James A. Bednar    schedule 31.05.2017
comment
Ой, очень мило! Есть ли какие-либо мысли по поводу второй части, то есть использования только выборок данных, а не диапазонов графика? Возможно, это будет работать автоматически, если я правильно передам параметры инструмента. - person Ben Farmer; 31.05.2017
comment
Где-то в документации должны быть примеры использования выбора данных, но если вы их не видите, спросите об этом в канал gitter. - person James A. Bednar; 01.06.2017

Работая с ответом Джеймса (https://stackoverflow.com/a/44288019/1447953), я расширил пример в вопрос к следующему. Он принимает один график в качестве «главного» источника управления и отображает только данные, которые появляются в диапазонах данных этого графика, на группу «подчиненных» графиков. Было бы неплохо иметь двусторонние отношения, но и так это круто.

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)
person Ben Farmer    schedule 31.05.2017