Search code examples
pythonpandasplotly

Remove gaps from unused categories in plotly python facet group bar plot


Is there an easy way to remove the gaps between the bars belonging to a single group? Just to make that clear, in my case the "actions" in the example data will never overlap across the facetting variable "animal", so these values will always be missing for the "other" "animal".

EDIT: as asked in comments, a gap within a subplot is desired (e.g. the category in general is used, only one instance is missing), to keep a consistent layout per subplot. Just the space reserved for categories exclusively belonging to another subplot should be removed.

import pandas as pd
import plotly.express as px
import plotly.graph_objects as go

data = [
    [1, 10, "dog", "run"], 
    [2, 15, "dog", "run"],
    [2, 13, "fish", "dive"],
    [1, 14, "fish", "swim"],
    [2, 13, "dog", "bark"],
    [1, 12, "dog", "growl"],
    [2, 12, "dog", "growl"],
    [1, 16, "fish", "dive"],
    [2, 7, "fish", "blub"],
    [1, 7, "fish", "swim"]
]
df = pd.DataFrame(data, columns=['day', 'temperature', "animal", "action"])

fig = px.bar(
        df,
        x=df["temperature"],
        y=df["day"].astype(str), # to use only existing values, 
        color="action",
        barmode="group",
        orientation="h",
        facet_row="animal",
        height=600
    )
fig.show()

grouped_bar_plot_with_facets


Solution

  • I've tried many things. The closest I got was by splitting the bars. I know it is not exactly what you want, but at least it is something close.

    data = [
        [1, 10, "dog", "run"], 
        [2, 15, "dog", "run"],
        [2, 13, "fish", "dive"],
        [1, 14, "fish", "swim"],
        [2, 13, "dog", "bark"],
        
        [1, 12, "dog", "growl"],
        [2, 12, "dog", "growl"],
        [1, 16, "fish", "dive"],
        [2, 7, "fish", "blub"],
        [1, 7, "fish", "swim"]
    ]
    df = pd.DataFrame(data, columns=['day', 'temperature', "animal", "action"])
    
    # take all unique animals
    animals = df['animal'].unique()
    print(animals) # prints ['dog', 'fish']
    
    # for each animal in list, create the plot and print it
    for a in animals:
        df_temp=df.loc[df['animal'] == a]
        fig = px.bar(
                df_temp,
                x=df_temp["temperature"],
                y=df_temp["day"].astype(str), # to use only existing values, 
                color="action",
                barmode="group",
                orientation="h",
                facet_row="animal",
                height=300
            )
        
        fig.show()
    
    

    Please let me know if the solution satisfies you.