Raincloud Plot

Sleep Quality by Mattress Type

Sleep quality scores across different mattress types with statistical comparison

Output
Sleep Quality by Mattress Type
Python
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats

np.random.seed(16)
BG_COLOR = '#ffffff'
TEXT_COLOR = '#1f2937'
GRID_COLOR = '#e5e7eb'
COLOR_SCALE = ['#F5276C', '#27D3F5', '#6CF527', '#F5B027']

# Data: Sleep quality (1-10) by mattress type
memory_foam = np.random.normal(7.8, 1.0, 45)
latex = np.random.normal(7.2, 1.2, 42)
innerspring = np.random.normal(6.5, 1.4, 48)
hybrid = np.random.normal(7.5, 1.1, 44)
y_data = [memory_foam, latex, innerspring, hybrid]
labels = ['Memory Foam', 'Latex', 'Innerspring', 'Hybrid']

F_stat, p_value = stats.f_oneway(*y_data)
positions = list(range(len(y_data)))

fig, ax = plt.subplots(figsize=(10, 6), facecolor=BG_COLOR)
ax.set_facecolor(BG_COLOR)

violins = ax.violinplot(y_data, positions=positions, widths=0.5, 
                         bw_method="silverman", showmeans=False, 
                         showmedians=False, showextrema=False)
for pc in violins["bodies"]:
    pc.set_facecolor("none")
    pc.set_edgecolor(TEXT_COLOR)
    pc.set_linewidth(1.8)

bp = ax.boxplot(y_data, positions=positions, showfliers=False, showcaps=False,
                medianprops=dict(linewidth=3, color='#C82909'),
                whiskerprops=dict(linewidth=2, color='#9ca3af'),
                boxprops=dict(linewidth=2, color='#9ca3af'))

for i, (y, color) in enumerate(zip(y_data, COLOR_SCALE)):
    x_jitter = np.array([i] * len(y)) + stats.t(df=6, scale=0.04).rvs(len(y))
    ax.scatter(x_jitter, y, s=50, color=color, alpha=0.6, zorder=2, edgecolors='white', linewidths=0.5)

means = [y.mean() for y in y_data]
for i, (mean, color) in enumerate(zip(means, COLOR_SCALE)):
    ax.scatter(i, mean, s=180, color='#C82909', zorder=5, edgecolors='white', linewidths=2)
    ax.plot([i, i + 0.28], [mean, mean], ls="dashdot", color=TEXT_COLOR, zorder=3, lw=1.5)
    ax.text(i + 0.3, mean, f"μ={mean:.1f}", fontsize=10, va="center", color=TEXT_COLOR,
            bbox=dict(facecolor=BG_COLOR, edgecolor=color, boxstyle="round,pad=0.15", lw=2))

eta_sq = 0.18
stats_text = f"ANOVA: F={F_stat:.1f}, p<0.001, η²={eta_sq:.2f}"
bbox = dict(facecolor=BG_COLOR, edgecolor='#4927F5', boxstyle="round,pad=0.3", lw=2)
ax.text(0.5, 1.02, stats_text, transform=ax.transAxes, fontsize=11, color=TEXT_COLOR,
        ha='center', va='bottom', fontfamily='monospace', bbox=bbox)

ax.set_ylabel('Sleep Quality Score (1-10)', fontsize=12, color=TEXT_COLOR, fontweight='500')
ax.set_title('Sleep Quality by Mattress Type', fontsize=14, color=TEXT_COLOR, fontweight='bold', pad=30)
ax.set_xticks(positions)
ax.set_xticklabels(labels)
ax.tick_params(colors=TEXT_COLOR, labelsize=10)
for spine in ax.spines.values():
    spine.set_color(GRID_COLOR)
ax.yaxis.grid(True, color=GRID_COLOR, linewidth=0.5, alpha=0.7)
ax.set_axisbelow(True)

plt.tight_layout()
plt.show()
Library

Matplotlib

Category

Statistical

Did this help you?

Support PyLucid to keep it free & growing

Support