Bokeh甘特图样式堆叠水平条形图空白及JS报错问题
Hey there, let's figure out why your Gantt-style chart is showing up blank and throwing that JS error. The main issues are with how you're handling the data source and misusing the hbar_stack function for this use case. Here's the breakdown and fix:
What's Going Wrong
You can't pass a GroupBy object directly to ColumnDataSource
When you dosource=ColumnDataSource(grouped), you're giving Bokeh a pandas GroupBy object instead of a structured data format it can understand (like a DataFrame or dictionary). This confuses Bokeh's JS rendering, leading to the "Unable to get property 'length' of undefined..." error.hbar_stackisn't meant for Gantt chartshbar_stackis designed to stack numerical values from multiple series (e.g., adding up task durations per org). But a Gantt chart needs to show tasks as time-based segments on each org's row, not stacked values.
Fixed Code & Step-by-Step Explanation
First, Prep Your Data
Make sure your date columns are properly typed, then calculate task durations (or just use start/end dates directly):
import pandas as pd from bokeh.plotting import figure, show from bokeh.models import ColumnDataSource, FactorRange # If you already have your df, skip this sample data setup sample_data = [ ["o1", "t1", "2019-11-19", "2019-11-23"], ["o1", "t2", "2019-11-23", "2019-11-27"], ["o1", "t3", "2019-11-27", "2019-12-01"], ["o1", "t4", "2019-12-02", "2019-12-06"], ["o2", "t1", "2019-11-20", "2019-11-24"], ["o2", "t2", "2019-11-24", "2019-11-28"], ["o2", "t3", "2019-12-01", "2019-12-05"], ["o2", "t4", "2019-12-05", "2019-12-09"], ["o3", "t1", "2019-11-20", "2019-11-24"], ["o3", "t2", "2019-11-24", "2019-11-28"], ["o3", "t3", "2019-12-01", "2019-12-05"], ["o3", "t4", "2019-12-05", "2019-12-09"], ] df = pd.DataFrame(sample_data, columns=["Org", "Task", "Start", "Finish"]) # Convert date columns to datetime (critical for Bokeh's datetime axis) df["Start"] = pd.to_datetime(df["Start"]) df["Finish"] = pd.to_datetime(df["Finish"])
Now Build the Gantt Chart
We'll use hbar instead of hbar_stack, since we need to plot each task as a time segment on its org's row:
# Get unique orgs for the y-axis orgs = df["Org"].unique().tolist() # Create the figure p = figure( title='Project Schedule', x_axis_type='datetime', y_range=FactorRange(factors=orgs), # Ensures y-axis shows org names correctly width=800, height=450 ) # Plot each task as a horizontal bar using start/end dates p.hbar( y='Org', left='Start', right='Finish', height=0.8, source=ColumnDataSource(df), legend_field='Task', alpha=0.7 ) # Tweak the chart for readability p.legend.location = "top_right" p.xaxis.axis_label = "Date" p.yaxis.axis_label = "Organization" # Show the chart show(p)
If You Actually Want Stacked Bars (Not Gantt)
If you meant to stack task durations per org (e.g., total time spent per org across tasks), here's how to use hbar_stack correctly by reshaping your data to wide format:
# Reshape data to wide format (one column per task) wide_df = df.pivot(index='Org', columns='Task', values=(df["Finish"] - df["Start"]).dt.days).fillna(0) # Create data source source = ColumnDataSource(wide_df.reset_index()) # Build stacked bar chart p = figure( title='Total Task Duration per Org', y_range=wide_df.index.tolist(), x_axis_label='Total Days', width=800, height=450 ) # Stack the task duration columns p.hbar_stack(wide_df.columns.tolist(), y='Org', height=0.8, source=source) show(p)
内容的提问来源于stack exchange,提问作者Wf19

