Hi @Mauz a small follow up. I tried to omit the gaps using plotly.graph_objects
. I admit, that this solution is quite laborious and far from perfect but it might work as a stating point for you.
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=cat_num,
cols=1,
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['types'],
x=group['values'],
orientation='h',
marker_color=colors,
name=name,
),
row=idx,
col=1
)
# 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_yaxes(title_text=name, row=idx, col=1)
# 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()
which produces: