Following on from the response here How to specify the x coordinate on a grouped bar chart on plotly?
I would like to get ALL the x coords, programatically.
I can get a working solution by playing around with hard coded numbers like:
import plotly.express as px
import plotly.graph_objects as go
import numpy as np
df = px.data.tips()
print(df.head())
fig = px.histogram(
df, x="sex", y="total_bill", color="time", barmode="group", height=400
)
# Add secondary x-axis that overlays categorical xaxis
fig.layout.xaxis2 = go.layout.XAxis(
overlaying='x', range=[0, 2], showticklabels=False)
# Add a line traces, and associate with the second xaxis
bargap = 0.2
for i in range(2):
x = bargap/2 + (1-bargap)/4
y = [1111]
print(111,x, y)
scatt = fig.add_scatter(x=[i+x], y=y, xaxis='x2',
showlegend=False, line={'color': 'gray'})
x *=2.3
print(22222,x, y)
scatt = fig.add_scatter(x=[i+x], y=y, xaxis='x2',
showlegend=False, line={'color': 'gray'})
fig
But I need a dynamic solution that works when I change color to day:
fig = px.histogram(
df, x="sex", y="total_bill", color="day", barmode="group", height=400
)
and then have 4 boxes in the sub plot. In the data I'm working with there's always a different number of plots and sub plots.
I really hope the devs from plotly can help with this, it's the first major limitation I have come up against using plotly.
Found it.
import plotly.express as px
df = px.data.tips()
# Use primary and secondary in your function to vary
primary = 'day'
secondary = 'sex'
fig = px.histogram(df, x=primary, y="total_bill", color=secondary, barmode="group", height=400)
nPri = len(df[primary].unique())
nSec = len(df[secondary].unique())
N = nPri
# Group centers
xrange = N-1 # the underlying x-axis is scaled with N automatically
xGp = [xrange * n / (N-1) for n in range(N)]
# Plot group centers
for ix in xGp:
fig.add_vline(x=ix)
bargap = 0.2 # I tried it with some variation. Still works.
fig.layout.bargap = bargap
# Calculate bar sizing
gpWidth = 1 - bargap
barWidth = gpWidth / nSec
# Left and right edges of each group
gpEdges = [(x - gpWidth / 2, x + gpWidth / 2) for x in xGp]
for ix1, ix2 in gpEdges:
gpRange = ix2 - ix1 # group range
xB = [ix1 + barWidth/2 + barWidth * n for n in range(nSec)] # list of x coordinates of each bar in the group
print(xB)
for x in xB:
fig.add_vline(x=x, line_color='blue')
fig.show()