I am trying to generate a stacked bar chart with plotly, specifically one that is "100%-stacked," like this:-
https://www.python-graph-gallery.com/13-percent-stacked-barplot
I am using the following code:-
import plotly
import plotly.graph_objects as go
import numpy as np
binnum_attr=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
tnl_attr=[164549.654, 278570.473, 201857.2155, 146326.9935, 116167.091, 98121.201, 384025.989, 786854.992, 502627.797, 306844.9995, 452795.6745, 271533.2325, 143591.5138]
pop_attr=[296699, 195322, 82853, 42382, 26001, 17926, 47187, 46586, 15508, 6500, 6412, 2339, 785]
verbose_customdata = np.stack((binnum_attr, tnl_attr, pop_attr), axis=-1)
fig = go.Figure(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['3.618', '1.526', '0.899', '0.674', '0.587', '0.566', '0.632', '0.411', '0.139', '0.081', '0.046', '0.024', '0.060'], customdata=verbose_customdata, legendgroup="M0", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M0 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M0', marker_color='rgb(128,128,128)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['36.797', '21.312', '12.348', '9.136', '8.275', '8.028', '9.105', '5.944', '2.473', '1.225', '0.725', '0.394', '0.377'], customdata=verbose_customdata, legendgroup="M1", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M1 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M1', marker_color='rgb(230,25,75)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['45.265', '40.620', '30.699', '23.548', '20.190', '18.252', '18.068', '13.085', '6.579', '3.656', '1.950', '1.343', '2.040'], customdata=verbose_customdata, legendgroup="M2", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M2 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M2', marker_color='rgb(60,180,75)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['12.552', '28.142', '34.866', '33.760', '30.362', '27.477', '22.317', '16.624', '10.221', '6.285', '3.853', '2.342', '3.101'], customdata=verbose_customdata, legendgroup="M3", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M3 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M3', marker_color='rgb(0,130,200)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['1.572', '7.198', '17.117', '24.482', '27.654', '28.867', '27.013', '22.357', '16.369', '13.342', '9.081', '6.584', '7.308'], customdata=verbose_customdata, legendgroup="M4", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M4 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M4', marker_color='rgb(245,130,48)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['0.177', '1.028', '3.369', '7.020', '10.741', '13.425', '16.108', '16.946', '13.654', '11.075', '7.060', '3.919', '3.424'], customdata=verbose_customdata, legendgroup="M5", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M5 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M5', marker_color='rgb(145,30,180)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['0.014', '0.147', '0.539', '0.898', '1.445', '2.123', '3.598', '7.842', '8.837', '7.916', '6.015', '4.466', '4.884'], customdata=verbose_customdata, legendgroup="M6", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M6 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M6', marker_color='rgb(70,240,240)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['0.003', '0.012', '0.120', '0.309', '0.460', '0.801', '2.013', '7.288', '10.854', '10.506', '6.766', '3.984', '2.921'], customdata=verbose_customdata, legendgroup="M7", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M7 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M7', marker_color='rgb(0,0,128)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['0.000', '0.001', '0.018', '0.075', '0.142', '0.279', '0.579', '4.052', '9.357', '10.690', '11.111', '9.456', '8.756'], customdata=verbose_customdata, legendgroup="M8", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M8 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M8', marker_color='rgb(210,245,80)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['0.003', '0.010', '0.019', '0.043', '0.086', '0.103', '0.300', '2.427', '7.132', '9.093', '8.937', '7.208', '4.578'], customdata=verbose_customdata, legendgroup="M9", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M9 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M9', marker_color='rgb(0,128,128)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['0.000', '0.000', '0.002', '0.017', '0.033', '0.051', '0.149', '1.564', '5.752', '9.613', '12.453', '15.218', '13.762'], customdata=verbose_customdata, legendgroup="M10", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M10 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M10', marker_color='rgb(220,190,255)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['0.000', '0.003', '0.004', '0.028', '0.019', '0.022', '0.068', '0.558', '3.286', '5.387', '9.235', '9.583', '6.008'], customdata=verbose_customdata, legendgroup="M11", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M11 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M11', marker_color='rgb(170,255,195)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['0.000', '0.000', '0.000', '0.002', '0.001', '0.001', '0.036', '0.732', '4.020', '8.839', '15.911', '25.388', '20.153'], customdata=verbose_customdata, legendgroup="M12", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M12 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M12', marker_color='rgb(255,215,180)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['0.000', '0.000', '0.000', '0.003', '0.003', '0.005', '0.014', '0.119', '0.810', '1.324', '3.969', '5.143', '7.068'], customdata=verbose_customdata, legendgroup="M13", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M13 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M13', marker_color='rgb(0,0,0)', marker_opacity=1.0))
fig.add_trace(go.Bar(x=['0~1', '1~2', '2~3', '3~4', '4~5', '5~6', '6~11', '11~26', '26~41', '41~55', '55~94', '94~158', '158~1644'], y=['0.000', '0.000', '0.000', '0.004', '0.000', '0.000', '0.000', '0.050', '0.517', '0.967', '2.888', '4.948', '15.559'], customdata=verbose_customdata, legendgroup="M14", hovertemplate='<b>Bin: %{customdata[0]: .0f}</b><br>'+'<b>M14 portion: %{y:.2f}%</b><br>'+'<b>Total length (all layers): %{customdata[1]:.2f}</b><br>'+'<b>Nets: %{customdata[2]: .0f}</b><br>', name='M14', marker_color='rgb(128,0,0)', marker_opacity=1.0))
fig.update_layout(barmode='stack')
fig.update_layout(title_text='<b>Metal Layer Usage by Length: euunit n3</b>', title_font_size=28, yaxis=dict(title='<b>Metal Layer Usage (%)</b>', titlefont_size=20, showticklabels=False), xaxis=dict(title='<b>Net Length Range (um)</b>', titlefont_size=20, tickfont_size=16))
fig.update_layout(legend=dict(font=dict(size=14),borderwidth=1))
fig.show()
...however, the outcome looks like this:-
...I am not quite sure why the bars do not fully occupy the vertical height of the plot area. Does the sum total of numbers in each bin (e.g. 0~1, 1~2, etc.) have to add up to exactly 100? I am asking because due to rounding some add up to 100.001 and others 99.999, etc. Or am I supposed to declare some kind of special format (e.g. %) for the numbers in each column?
The plotly options are all relatively new to me, so I could very well be missing something simple. Does anyone have any suggestions? Note that barmode='relative' did not change the outcome.
Thanks!