Say I have a dataset of z-scores from different groups (classrooms, buildings, etc). We will use two groups in this example, but it could be more. I find Z-scores hard to interpret, so I want to plot them with a Normal(0,1) in the background to more easily see where in the bell curve they lie. The following is how I did it, using go.Bar, a secondary y-axis, and go.Line. I'm sure there are more ways to accomplish the same thing, and I am interested in learning from other approaches. How would you plot something like this? import pandas as pd import plotly.graph_objects as go from plotly.subplots import make_subplots # to enable multiple y-axes # For Normal distribution import numpy as np import matplotlib.pyplot as plt from scipy.stats import norm d = {'Name':['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'], 'Score':[1, 1.5, 4, 1.5, 1.5, 4, 2.5, 3, 2.5, 4], 'Building':['b', 'a', 'b', 'a', 'a', 'b', 'a', 'b', 'b', 'a'], 'count':[1,1,1,1,1,1,1,1,1,1]} df = pd.DataFrame(data=d) color_map = {'a': 'red', 'b': 'blue'} df['building_color'] = df['Building'].map(color_map) # Create figure with secondary y-axis fig2 = make_subplots(specs=[[{"secondary_y": True}]]) # Add building data and stack the bars fig2.add_trace(go.Bar(x=df[df['Building']=='a']['Score'], y=df[df['Building']=='a']['count'], name='A'), secondary_y=False) fig2.add_trace(go.Bar(x=df[df['Building']=='b']['Score'], y=df[df['Building']=='b']['count'], name='B'), secondary_y=False) fig2.update_layout(barmode='stack', yaxis_range=[0,18]) # Add Normal(0,1) mean=0 std=1 x=np.linspace(mean-4*std, mean+4*std, 300) y=norm(loc=mean, scale=std).pdf(x) normal_data = {'x':x, 'y':y} normal_df = pd.DataFrame(data=normal_data) fig2.add_trace(go.Line(x=normal_df['x'], y=normal_df['y']), secondary_y=True) fig2.update_layout(title='Visualizing z-scores on Normal curve', xaxis_title='Z-score', yaxis_title='Count', yaxis2_title='Prob') Continue reading...