首页 > 解决方案 > 使用滑块小部件过滤和更新交互式散景可视化

问题描述

我是 Python 新手,我正在尝试使用散景创建一些交互式可视化。目前,我正在尝试使用散点图汇总分组数据,该散点图具有下拉功能,允许用户交换不同的数据列。

我创建了一个模拟数据框,类似于我作为 csv 加载的真实数据框:-

Device,Column1,Column2,Column3,Column4,Hour,Day
aaa,98,59,56,57,22,Day one
aaa,29,10,22,14,15,Day one
aaa,21,4,72,25,13,Day one
aaa,87,87,13,83,1,Day one
aaa,41,46,81,25,9,Day one
aaa,85,42,16,12,15,Day one
aaa,73,5,32,19,12,Day one
aaa,84,16,30,34,5,Day one
aaa,28,11,46,63,15,Day one
aaa,50,86,83,48,17,Day one
aaa,74,37,79,48,19,Day one
aaa,40,88,67,79,17,Day one
bbb,1,19,34,6,2,Day one
bbb,5,26,75,25,13,Day one
bbb,27,1,10,84,19,Day one
bbb,62,87,4,51,2,Day one
bbb,71,24,66,6,9,Day one
bbb,49,75,18,67,7,Day one
bbb,51,15,74,35,12,Day one
bbb,38,94,65,32,8,Day one
bbb,23,1,21,26,2,Day one
bbb,83,67,76,7,1,Day one
bbb,87,25,5,86,12,Day one
bbb,58,28,33,71,22,Day one
bbb,18,8,16,13,14,Day one
bbb,89,20,71,39,19,Day one
bbb,60,22,69,79,10,Day one
bbb,93,9,9,9,12,Day one
bbb,76,34,60,21,21,Day one
bbb,39,37,52,23,15,Day one
bbb,45,87,61,96,20,Day one
ccc,92,96,29,97,8,Day one
ccc,62,72,83,45,15,Day one
ccc,42,58,28,94,12,Day one
ccc,45,76,78,24,18,Day one
ccc,58,11,33,55,8,Day one
ccc,4,14,86,9,2,Day one
ccc,21,22,2,78,22,Day one
ccc,11,3,33,41,6,Day one
ccc,57,96,72,48,10,Day one
ddd,28,59,23,66,13,Day one
ddd,62,93,71,42,11,Day one
ddd,6,96,67,50,19,Day one
ddd,4,61,28,29,7,Day one
ddd,71,80,78,2,13,Day one
ddd,59,88,19,56,5,Day one
eee,78,44,27,46,13,Day one
eee,70,54,62,31,14,Day one
eee,4,54,6,12,11,Day one
eee,49,82,37,10,1,Day one
eee,44,81,1,69,17,Day two
eee,59,60,19,9,11,Day two
eee,60,37,40,82,12,Day two
eee,8,17,26,52,18,Day two
eee,10,98,48,24,11,Day two
eee,79,85,73,54,19,Day two
eee,25,82,66,73,6,Day two
eee,8,50,21,28,18,Day two
eee,95,26,14,8,20,Day two
eee,57,22,77,68,5,Day two
eee,77,11,87,35,20,Day two
eee,13,13,16,19,17,Day two
fff,36,81,30,61,7,Day two
fff,24,66,75,94,9,Day two
fff,21,34,46,52,16,Day two
fff,44,92,2,40,0,Day two
fff,6,68,15,34,17,Day two
fff,41,68,16,57,12,Day two
fff,12,84,30,81,0,Day two
fff,42,8,38,43,2,Day two
fff,4,22,66,64,20,Day two
fff,95,37,96,36,21,Day two
fff,44,71,94,39,2,Day two
fff,7,69,28,4,0,Day two
fff,59,63,52,64,16,Day two
fff,29,3,24,83,14,Day two
fff,32,67,74,93,21,Day two
fff,6,73,15,49,14,Day two
fff,70,83,86,90,5,Day two
fff,16,73,82,72,2,Day two
fff,97,72,5,53,10,Day two
fff,36,83,12,58,12,Day two
fff,67,58,2,91,12,Day two
fff,19,81,28,64,11,Day two
fff,2,53,74,11,8,Day two
fff,68,27,78,8,19,Day two
fff,34,77,9,15,12,Day two
fff,50,51,23,88,22,Day two
fff,79,38,14,26,10,Day two
fff,4,41,50,85,9,Day two
fff,41,29,66,49,18,Day two
fff,34,3,51,17,5,Day two
fff,87,79,48,97,4,Day two
fff,66,41,51,16,12,Day two
fff,29,84,22,38,5,Day two
fff,51,50,87,29,2,Day two
fff,63,33,2,61,12,Day two
fff,38,6,20,86,1,Day two
fff,31,87,38,93,20,Day two
ggg,80,93,77,96,3,Day two

这是我用来创建交互式绘图的 Python 代码:-

import numpy as np
import pandas as pd
from bokeh.layouts import column, row
from bokeh.models import  Select
from bokeh.plotting import figure, output_file, curdoc
from bokeh.palettes import Spectral5



####################################################

#this is the data I have provided above, as read in as a csv
dataset = pd.read_csv('exampledata.csv')



groupeddf=dataset.groupby(['Day','Hour','Device'])[['Column1','Column2','Column3','Column4']].mean()
groupeddf.head(10)
grouped_device_counts=dataset.groupby(['Day','Hour','Device']).size()#get counts of devices
grouped_device_counts=grouped_device_counts.reset_index()
grouped_device_counts = grouped_device_counts.rename(columns= {0: 'Count'})#works
#merge
group_device_summary=pd.merge(groupeddf,grouped_device_counts, on=['Day','Hour','Device'])#works
group_device_summary["color"] = np.where(group_device_summary["Count"] > 3, "orange", "grey")
group_device_summary["alpha"] = np.where(group_device_summary["Count"] > 0, 0.9, 0.25)

group_device_summary.head(10)



# data cleanup
#group_device_summary.device_model = group_device_summary.device_model.astype(str)
#df.yr = group_device_summary.yr.astype(str)
#del df['name']
SIZES = list(range(6, 22, 3))
COLORS = Spectral5
N_SIZES = len(SIZES)
N_COLORS = len(COLORS)
columns = sorted(group_device_summary.columns)
discrete = [x for x in columns if group_device_summary[x].dtype == object]
continuous = [x for x in columns if x not in discrete]

#source=ColumnDataSource(columns)

#TOOLTIPS=[
 #   ("device", "@device_model")
#]

def create_figure():
    xs = group_device_summary[x.value].values
    ys = group_device_summary[y.value].values
    x_title = x.value.title()
    y_title = y.value.title()

    kw = dict()
    if x.value in discrete:
        kw['x_range'] = sorted(set(xs))
    if y.value in discrete:
        kw['y_range'] = sorted(set(ys))
    kw['title'] = "%s vs %s" % (x_title, y_title)

    p = figure(height=600, width=800, tools='pan,box_zoom,hover,reset', **kw)
    p.xaxis.axis_label = x_title
    p.yaxis.axis_label = y_title

    if x.value in discrete:
        p.xaxis.major_label_orientation = pd.np.pi / 4

    sz = 9
    if size.value != 'None':
        if len(set(group_device_summary[size.value])) > N_SIZES:
            groups = pd.qcut(group_device_summary[size.value].values, N_SIZES, duplicates='drop')
        else:
            groups = pd.Categorical(group_device_summary[size.value])
        sz = [SIZES[xx] for xx in groups.codes]

    c = "#31AADE"
    if color.value != 'None':
        if len(set(group_device_summary[color.value])) > N_COLORS:
            groups = pd.qcut(group_device_summary[color.value].values, N_COLORS, duplicates='drop')
        else:
            groups = pd.Categorical(group_device_summary[color.value])
        c = [COLORS[xx] for xx in groups.codes]

    p.circle(x=xs, y=ys, color=c, size=sz, line_color="white", alpha=0.6, hover_color='white', hover_alpha=0.5)

    return p


def update(attr, old, new):
    layout.children[1] = create_figure()


x = Select(title='X-Axis', value='Column1', options=columns)
x.on_change('value', update)

y = Select(title='Y-Axis', value='Column2', options=columns)
y.on_change('value', update)

size = Select(title='Size', value='None', options=['None'] + continuous)
size.on_change('value', update)

color = Select(title='Color', value='None', options=['None'] + discrete)
color.on_change('value', update)

controls = column(x, y, color, size, width=200)
layout = row(controls, create_figure())


output_file('scatter.html', title="Example")
curdoc().add_root(layout)
curdoc().title = "Crossfilter"#use curdoc to make it interactive
#show(layout)

期望的结果

我想添加一个滑块小部件,它将简单地通过“数据框”中的“小时”变量更新可视化。如下所示:-

slider = Slider(start=0, end=23,step=1,value=9,title='Hour')

谁能帮我在我现有的代码中实现它?我做了很多相当脆弱的尝试来让它适当地过滤和绘制数据,但是可视化没有启动(给我白屏)或绘图变为静态(无法更新)。

我认为有一个简单的解决方案,非常感谢任何帮助:)

标签: pythonwidgetbokehscatter-plotpandas-bokeh

解决方案


推荐阅读