Reduce the space between the bar groups?

Hi everyone,

I am having a problem with plotting multiple series as bar plot with plotly.go. It’s acceptable until I plot more than 4 groups of bars when I would start to get large spacing between bar groups like this:

I already tried setting bargap, and bargroupgap but it doesn’t reduce the space. Also, if I increase the width of bar there’s still huge amount of space between groups while bars witinin group overlap each other. Any ideas how to make this work?

    fig1 = go.Figure()
    
    unique_sample_short = mean_values['Sample_short'].unique()
    unique_names = mean_values['Name'].unique()
    
    color_sequence_api = getattr(px.colors.qualitative, colorscale, px.colors.qualitative.Plotly)
    name_to_color = {Name: color_sequence_api[i % len(color_sequence_api)] for i, Name in enumerate(unique_names)}
    
    names_added_to_legend = set()
    
    for sample in unique_sample_short:
        for Name in unique_names:
            subset = mean_values[(mean_values['Sample_short'] == sample) & (mean_values['Name'] == Name)]
            if not subset.empty:
                show_legend = Name not in names_added_to_legend
                names_added_to_legend.add(Name)
    
                fig1.add_trace(go.Bar(
                    x=[subset['Sample_short'].tolist(), subset['Sample_long'].tolist()],
                    y=subset['AssayPct'],
                    name=Name,
                    marker_color=name_to_color[Name],
                    showlegend=show_legend,
                ))
    
    fig1.update_layout(
        title_text=title,
        xaxis=dict(type="multicategory"),
        yaxis=dict(range=[lower_y, upper_y]),
        template=template,
    )

Hey @davzup89,

I answered a similar question a while ago, take a look at this:

Hi @AIMPED,

Thank you for your answer! Your solution with subplots works very nicely for me as far as bar widths go. However, it would stack one subplot upon another, instead of keeping them at same horizotal level. Can’ t figure how to stack them horizontaly with ‘Value’ on y axis.

# Create figure object
fig1 = go.Figure()

# Get unique values for 'Sample_short' and 'Name'
unique_Sample_short = mean_values['Sample_short'].unique()
unique_Names = mean_values['Name'].unique()

# Create a color sequence for API names
color_sequence_api = getattr(px.colors.qualitative, colorscale, px.colors.qualitative.Plotly)
Name_to_color = {Name: color_sequence_api[i % len(color_sequence_api)] for i, Name in enumerate(unique_Names)}

# Keep track of which API names have been added to the legend
Names_added_to_legend = set()


# Create base figure with subplots
fig1 = make_subplots(
    rows=len(unique_Sample_short), 
    cols=1,
    shared_xaxes=True, 
    shared_yaxes=True,
    vertical_spacing=0.05
)

# Add traces for each combination of 'Sample_short' and 'Name'
for idx, Sample in enumerate(unique_Sample_short, start=1):
    for Name in unique_Names:
        subset = mean_values[(mean_values['Sample_short'] == Sample) & (mean_values['Name'] == Name)]
        if not subset.empty:
            fig1.append_trace(
                go.Bar(
                    x=subset['Sample_long'],
                    y=subset['Value'],
                    name=Name,
                    marker_color=Name_to_color[Name],
                    orientation='v'
                ),
                row=idx,
                col=1
            )

# Set y-axis titles and other layout updates
for idx, Sample in enumerate(unique_Sample_short, start=1):
    fig1.update_yaxes(title_text=Sample, row=idx, col=1)

fig1.update_layout(
    title_text=title,
    template=template,
    height=600 
)
fig1.update_yaxes(showticklabels=False) 

Hey,

are you referring to this?

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
import plotly.express as px
import numpy as np

# set number of categories
cat_num = 5

# set number of types
type_num = 20

# create data
categories = []
for i in range(1, cat_num + 1):
    categories.extend([f'category_{i}'] * type_num)

types = [f'type_{i}' for i in range(type_num)] * cat_num    

values = np.random.randint(1, 40, cat_num * type_num)    

# create DataFrame
df = pd.DataFrame({'categories': categories, 'values': values, 'types': types})

# delete some rows from the DataFrame so that category_1 has fewer "types"
df = df.drop(range(1,15))

# groupby categories
gb = df.groupby('categories')

# create base figure
fig = make_subplots(
    rows=1, 
    cols=cat_num,
    shared_xaxes=True, 
    shared_yaxes=False,
    vertical_spacing=0.05
)

# create a lookup so that each "type" gets always the same color
color_code = {t: c for t,c in zip(df.types.unique(), px.colors.qualitative.Alphabet)}

for idx, name_group in enumerate(gb, start=1):
    name, group = name_group
    
    # map colors to existing "types"
    colors = [color_code[t] for t in group['types']]
    
    # append traces to figure
    fig.append_trace(
        go.Bar(
            y=group['values'], 
            x=group['types'],
            orientation='v',
            marker_color=colors,
            name=name,
        ),
        row=1,
        col=idx
    )

# create y-axis titles, start from 1 due to internal subplots row numbering
for idx, name_group in enumerate(gb, start=1):
    name, group = name_group
    fig.update_xaxes(title_text=name, row=1, col=idx)

# do not show traces in legend, hide ticklabels, set height
fig.update_traces(showlegend=False)
fig.update_yaxes(showticklabels=False)        
fig.update_layout(height=600)
fig.show()

Yes. With my code, I get appropriate bar widths but vertically stacked subplots:

Is there a way to stack them horizontally?

You need to swap cols/rows and all subsequent references to them. 1 row an n columns

Hard to tell without your data, though

1 Like