You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Bokeh复选框基于多DataFrame分类列切换条形图显示

Solution for Multi-Category Bar Toggle in Bokeh

Here's a practical implementation that lets you toggle bar visibility using checkboxes for multiple categorical columns. The solution uses Bokeh's CustomJS to handle the multi-category filtering logic without needing deep JavaScript expertise.

Step 1: Setup Dependencies and Sample Data

First, import required modules and create a sample DataFrame matching your structure:

from bokeh.models import ColumnDataSource, CheckboxGroup, CustomJS
from bokeh.plotting import figure, show
from bokeh.layouts import column
import pandas as pd
import numpy as np

# Generate sample data matching your schema
np.random.seed(42)
sample_ids = [f"Sample {i}" for i in range(1, 11)]
y_values = np.random.randint(10, 50, size=10)
sizes = np.random.choice(['big', 'small'], size=10)
designs = np.random.choice(['A', 'B'], size=10)
colors = np.random.choice(['blue', 'red'], size=10)

df = pd.DataFrame({
    'x': sample_ids,
    'y': y_values,
    'size': sizes,
    'design': designs,
    'color': colors
})

Step 2: Create Data Source and Base Plot

We add a visible column to our data source to track which bars should be displayed:

# Create data source with visibility tracking
source = ColumnDataSource(data=dict(
    x=df['x'],
    y=df['y'],
    size=df['size'],
    design=df['design'],
    color=df['color'],
    visible=[True]*len(df)  # Start with all bars visible
))

# Create the bar plot
p = figure(
    x_range=sample_ids,
    title="Sample ID vs Y Value (Filterable by Categories)",
    x_axis_label="Sample ID",
    y_axis_label="Y Value",
    height=400,
    width=800
)
p.vbar(x='x', top='y', width=0.5, source=source, visible='visible')

Step 3: Add Checkbox Group

Create checkboxes for all categorical values:

# Define checkbox group with all category options
checkbox_group = CheckboxGroup(
    labels=['big', 'small', 'A', 'B', 'blue', 'red'],
    active=[0,1,2,3,4,5],  # All checked by default
    width=150
)

Step 4: CustomJS Callback for Filtering

This callback checks if each bar meets all selected category criteria and updates visibility accordingly:

callback = CustomJS(args=dict(source=source, checkbox=checkbox_group), code="""
    const data = source.data;
    const active_checkboxes = checkbox.active;
    
    // Map checkbox indices to category values
    const selected_sizes = new Set();
    if (active_checkboxes.includes(0)) selected_sizes.add('big');
    if (active_checkboxes.includes(1)) selected_sizes.add('small');
    
    const selected_designs = new Set();
    if (active_checkboxes.includes(2)) selected_designs.add('A');
    if (active_checkboxes.includes(3)) selected_designs.add('B');
    
    const selected_colors = new Set();
    if (active_checkboxes.includes(4)) selected_colors.add('blue');
    if (active_checkboxes.includes(5)) selected_colors.add('red');
    
    // Update visibility for each bar
    const visible = data['visible'];
    const sizes = data['size'];
    const designs = data['design'];
    const colors = data['color'];
    
    for (let i = 0; i < sizes.length; i++) {
        visible[i] = selected_sizes.has(sizes[i]) && 
                     selected_designs.has(designs[i]) && 
                     selected_colors.has(colors[i]);
    }
    
    // Trigger plot update
    source.change.emit();
""")

# Link callback to checkbox changes
checkbox_group.js_on_change('active', callback)

Full Working Code

Combine all parts and display the interactive plot:

from bokeh.models import ColumnDataSource, CheckboxGroup, CustomJS
from bokeh.plotting import figure, show
from bokeh.layouts import column
import pandas as pd
import numpy as np

# Generate sample data
np.random.seed(42)
sample_ids = [f"Sample {i}" for i in range(1, 11)]
y_values = np.random.randint(10, 50, size=10)
sizes = np.random.choice(['big', 'small'], size=10)
designs = np.random.choice(['A', 'B'], size=10)
colors = np.random.choice(['blue', 'red'], size=10)

df = pd.DataFrame({
    'x': sample_ids,
    'y': y_values,
    'size': sizes,
    'design': designs,
    'color': colors
})

# Create data source
source = ColumnDataSource(data=dict(
    x=df['x'],
    y=df['y'],
    size=df['size'],
    design=df['design'],
    color=df['color'],
    visible=[True]*len(df)
))

# Create plot
p = figure(
    x_range=sample_ids,
    title="Filterable Bar Chart",
    x_axis_label="Sample ID",
    y_axis_label="Y Value",
    height=400,
    width=800
)
p.vbar(x='x', top='y', width=0.5, source=source, visible='visible')

# Create checkboxes
checkbox_group = CheckboxGroup(
    labels=['big', 'small', 'A', 'B', 'blue', 'red'],
    active=[0,1,2,3,4,5],
    width=150
)

# Callback logic
callback = CustomJS(args=dict(source=source, checkbox=checkbox_group), code="""
    const data = source.data;
    const active_checkboxes = checkbox.active;
    
    const selected_sizes = new Set();
    if (active_checkboxes.includes(0)) selected_sizes.add('big');
    if (active_checkboxes.includes(1)) selected_sizes.add('small');
    
    const selected_designs = new Set();
    if (active_checkboxes.includes(2)) selected_designs.add('A');
    if (active_checkboxes.includes(3)) selected_designs.add('B');
    
    const selected_colors = new Set();
    if (active_checkboxes.includes(4)) selected_colors.add('blue');
    if (active_checkboxes.includes(5)) selected_colors.add('red');
    
    const visible = data['visible'];
    const sizes = data['size'];
    const designs = data['design'];
    const colors = data['color'];
    
    for (let i = 0; i < sizes.length; i++) {
        visible[i] = selected_sizes.has(sizes[i]) && 
                     selected_designs.has(designs[i]) && 
                     selected_colors.has(colors[i]);
    }
    
    source.change.emit();
""")

checkbox_group.js_on_change('active', callback)

# Display layout
show(column(checkbox_group, p))

Key Logic Explanation

  • Each checkbox maps to a specific categorical value (e.g., index 0 = 'big', index 2 = 'A').
  • We use Set objects to efficiently check if a bar's category values are selected.
  • A bar remains visible only if all its category values match the selected checkboxes (e.g., a bar with size='big', design='A', color='red' will only show if all three corresponding checkboxes are checked).
  • The source.change.emit() command tells Bokeh to refresh the plot with updated visibility values.

Content of the question originates from Stack Exchange, question author Rory Majule

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 03:50:27