如何用Plotly/Matplotlib绘制带σ值的正态分布曲线?
Got it, let's fix that underwhelming normal distribution plot for you! The core issue with your original code is that you're using raw (even sorted) data points to calculate the PDF. Real-world error data rarely has perfectly evenly spaced values, which leads to jagged, misaligned curves. Below are two robust solutions—one with Matplotlib (great for static reports) and one with Plotly (perfect for interactive exploration)—both including σ markers and clear, publication-ready visuals.
Matplotlib Solution
This approach combines a histogram of your data with a smooth normal curve, plus explicit markers for the mean and ±1σ/±2σ/±3σ ranges:
import numpy as np import scipy.stats as stats import matplotlib.pyplot as plt # Assume mydata is your error dataset mymean = np.mean(mydata) mystd = np.std(mydata) # Generate evenly spaced x-values for a smooth curve (3σ range covers ~99.7% of data) x = np.linspace(mymean - 3*mystd, mymean + 3*mystd, 1000) # Calculate PDF for these x-values pdf = stats.norm.pdf(x, mymean, mystd) # Create figure and axes fig, ax = plt.subplots(figsize=(10, 6)) # Plot histogram of your data (normalized to match PDF scale) ax.hist(mydata, bins=30, density=True, alpha=0.6, color='#1f77b4', label='Error Data') # Plot smooth normal curve ax.plot(x, pdf, color='#ff7f0e', linewidth=2, label=f'Normal Fit (μ={mymean:.2f}, σ={mystd:.2f})') # Add vertical lines for mean and σ ranges ax.axvline(mymean, color='#2ca02c', linestyle='--', linewidth=2, label='Mean (μ)') ax.axvline(mymean + mystd, color='#d62728', linestyle=':', linewidth=1.5, label='μ+σ') ax.axvline(mymean - mystd, color='#d62728', linestyle=':', linewidth=1.5) ax.axvline(mymean + 2*mystd, color='#9467bd', linestyle=':', linewidth=1.5, label='μ+2σ') ax.axvline(mymean - 2*mystd, color='#9467bd', linestyle=':', linewidth=1.5) ax.axvline(mymean + 3*mystd, color='#8c564b', linestyle=':', linewidth=1.5, label='μ+3σ') ax.axvline(mymean - 3*mystd, color='#8c564b', linestyle=':', linewidth=1.5) # Add labels, title, legend ax.set_xlabel('Error Value') ax.set_ylabel('Probability Density') ax.set_title('Normal Distribution of Error Data with σ Markers') ax.legend() plt.tight_layout() plt.show()
Why this works:
- We use
np.linspaceto generate 1000 evenly spaced points across the 3σ range, which ensures a smooth, continuous curve (no jagged edges from raw data gaps). - The histogram is normalized (
density=True) to match the PDF scale, making it easy to compare the data to the ideal normal fit. - Clear markers for mean and σ ranges make the plot informative at a glance.
Plotly Solution
For interactive exploration (zoom, hover tooltips, toggleable elements), Plotly is perfect. This code creates an interactive plot with the same key elements:
import numpy as np import scipy.stats as stats import plotly.graph_objects as go # Assume mydata is your error dataset mymean = np.mean(mydata) mystd = np.std(mydata) # Generate smooth x-values x = np.linspace(mymean - 3*mystd, mymean + 3*mystd, 1000) pdf = stats.norm.pdf(x, mymean, mystd) # Create figure fig = go.Figure() # Add histogram fig.add_trace(go.Histogram( x=mydata, nbinsx=30, histnorm='probability density', opacity=0.6, name='Error Data', marker_color='#1f77b4' )) # Add normal curve fig.add_trace(go.Scatter( x=x, y=pdf, mode='lines', name=f'Normal Fit (μ={mymean:.2f}, σ={mystd:.2f})', line=dict(color='#ff7f0e', width=2) )) # Add vertical lines for mean and σ ranges # Mean line fig.add_vline(x=mymean, line_dash='dash', line_color='#2ca02c', annotation_text='μ', annotation_position='top right') # ±1σ lines fig.add_vline(x=mymean + mystd, line_dash='dot', line_color='#d62728', annotation_text='μ+σ', annotation_position='top right') fig.add_vline(x=mymean - mystd, line_dash='dot', line_color='#d62728') # ±2σ lines fig.add_vline(x=mymean + 2*mystd, line_dash='dot', line_color='#9467bd', annotation_text='μ+2σ', annotation_position='top right') fig.add_vline(x=mymean - 2*mystd, line_dash='dot', line_color='#9467bd') # ±3σ lines fig.add_vline(x=mymean + 3*mystd, line_dash='dot', line_color='#8c564b', annotation_text='μ+3σ', annotation_position='top right') fig.add_vline(x=mymean - 3*mystd, line_dash='dot', line_color='#8c564b') # Update layout fig.update_layout( title='Interactive Normal Distribution of Error Data', xaxis_title='Error Value', yaxis_title='Probability Density', legend_title='Legend', width=900, height=500 ) fig.show()
Why this works:
- Interactive tooltips let you hover to see exact values for the histogram bars and curve points.
- You can zoom/pan to focus on specific ranges (like the ±1σ region) without regenerating the plot.
- The
histnorm='probability density'setting aligns the histogram with the PDF, just like the Matplotlib version.
内容的提问来源于stack exchange,提问作者ankushbraj

