Plotly甘特图同一子图添加多轨迹导致条形尺寸异常的解决方法咨询
I’ve run into exactly this issue before—when combining multiple color-coded traces from px.timeline into a single subplot, Plotly’s default grouping behavior messes up bar heights and pushes text out of view. Let’s break down why this happens and how to fix it.
Why This Happens
When you generate a timeline with multiple colors (using the color parameter), px.timeline creates a separate trace for each color. Each trace treats your ProdName values as distinct y-axis categories by default. When you add these traces to the same subplot, Plotly stacks or spaces them out instead of aligning them under the same product category, which distorts bar heights and breaks text display.
The Fix: Manual Y-Coordinate Alignment
We need to force all traces to use the same y-axis positions for matching ProdName values, and set a consistent bar height. Here’s your modified code with these changes:
Modified Code
def create_plot(self, date_start, date_end): df = self.filtered_df customers = df['Customer'].unique() pixel = 35 customer_plots = dict() heights = [] for customer in customers: customer_df = df.loc[df['Customer'] == customer] # Create a fixed order and numeric mapping for ProdName values prod_order = customer_df['ProdName'].unique() prod_to_y = {prod: idx for idx, prod in enumerate(prod_order)} total_products = len(prod_order) # Generate the timeline as before fig = px.timeline( customer_df, x_start='StartDate', y='ProdName', x_end='DueDate', text='DocNum', color='Estat' ) fig.update_traces(textposition="inside") # Standardize y-values and bar height across all traces for trace in fig['data']: # Replace string ProdName values with our fixed numeric y-coordinates trace['y'] = [prod_to_y[prod] for prod in trace['y']] # Set a consistent bar height (adjust this value to your preference) trace['width'] = 0.8 customer_plots[customer] = fig heights.append(5 + total_products * pixel) # Build subplots as before fig_sub = make_subplots( rows=len(customer_plots), row_heights=heights, subplot_titles=list(customer_plots.keys()) ) fig_sub.update_xaxes(type='date') for i, (customer, plot) in enumerate(customer_plots.items()): # Recreate the ProdName mapping for this customer prod_order = df.loc[df['Customer'] == customer]['ProdName'].unique() prod_to_y = {prod: idx for idx, prod in enumerate(prod_order)} for trace in plot['data']: fig_sub.add_trace(trace, row=i+1, col=1) # Customize y-axis to show ProdName labels instead of numbers fig_sub.update_yaxes( tickmode='array', tickvals=list(prod_to_y.values()), ticktext=list(prod_to_y.keys()), row=i+1, col=1 ) # Final layout adjustments fig_sub.update_layout( autosize=False, height=sum(heights), width=1500 ) for ax in fig_sub['layout']: if ax[:5] == 'xaxis': fig_sub['layout'][ax]['range'] = [date_start, date_end] fig_sub['layout'][ax]['dtick'] = 86400000.0 * 7 self.plot = fig_sub
Key Changes Explained
- Fixed Y-Coordinate Mapping: We create a numeric mapping for each customer’s
ProdNamevalues. This ensures that every trace uses the same y-position for the same product, so bars align correctly instead of being spaced out. - Consistent Bar Height: Setting
trace['width'](since it’s a horizontal bar,widthcontrols vertical height) ensures all bars have the same size, so text fits inside as expected. Tweak the0.8value if you need taller/shorter bars. - Custom Y-Axis Labels: We manually map the numeric y-values back to the original
ProdNamestrings, so the subplot axes remain readable.
Quick Tweaks to Try
- If text still doesn’t fit, adjust the
pixelvalue used to calculate row heights (increase it slightly to give more vertical space). - Play with the
trace['width']value—values between 0.7 and 0.9 usually work best for most cases.
内容的提问来源于stack exchange,提问作者Ferran Capallera Guirado

