Graphique en entonnoir
Les petites études « Pygmalion » sont-elles plus optimistes ? 19 effets des attentes des enseignants en fonction de leur erreur type, avec entonnoir pseudo-95 % et test d'Egger.

Chaque point est une étude : sa taille d'effet en abscisse, son erreur type en ordonnée (axe inversé), de sorte que les grandes études précises se trouvent en haut. En l'absence de biais, les points forment un entonnoir symétrique autour de l'effet combiné, dont 95 % se situent dans la région de pseudo-confiance (± 1,96 erreur type). S'il manque de petites études aux résultats nuls ou négatifs — biais de publication —, le bas de l'entonnoir est déséquilibré. Le test de régression d'Egger (écart normal réduit régressé sur la précision) quantifie cette asymétrie ; sa droite ajustée est en tirets.
Les données sont les 19 expériences sur les attentes des enseignants (effet « Pygmalion ») de Raudenbush (1984) : différences de moyennes standardisées du QI des élèves et leurs variances d'échantillonnage, saisies telles que publiées dans dat.raudenbush1985 du paquet R metafor. Les études les moins précises rapportent les effets les plus forts, et l'ordonnée à l'origine d'Egger est à la limite de la significativité. Une asymétrie ne prouve pas un biais de publication : ici, les petites études sont pour la plupart celles où les enseignants connaissaient leurs élèves depuis une semaine ou moins, situation dont Raudenbush a montré qu'elle produit des effets réellement plus forts. Le test d'Egger est une régression MCO de statsmodels.
Le code et le texte à l'intérieur des figures sont en anglais.
import matplotlib.pyplot as plt
import numpy as np
import statsmodels.api as sm
# Teacher-expectancy experiments (Raudenbush, 1984): standardised mean difference
# in pupil IQ and its sampling variance, as in metafor's dat.raudenbush1985
dp = np.array([0.03, 0.12, -0.14, 1.18, 0.26, -0.06, -0.02, -0.32, 0.27, 0.80, 0.54, 0.18,
-0.02, 0.23, -0.18, -0.06, 0.30, 0.07, -0.07])
vi = np.array([0.0156, 0.0216, 0.0279, 0.1391, 0.1362, 0.0106, 0.0106, 0.0484, 0.0269, 0.0630,
0.0912, 0.0497, 0.0835, 0.0841, 0.0253, 0.0279, 0.0193, 0.0088, 0.0303])
sp = np.sqrt(vi)
# Fixed-effect pooled estimate and Egger's test: z = b0 + b1 · precision
w = 1 / sp**2
pooled = np.sum(w * dp) / w.sum()
egger = sm.OLS(dp / sp, sm.add_constant(1 / sp)).fit()
b0, b1 = egger.params
fig, ax = plt.subplots(figsize=(9, 5.6))
s_grid = np.linspace(0, sp.max() * 1.1, 100)
ax.fill_betweenx(s_grid, pooled - 1.96 * s_grid, pooled + 1.96 * s_grid, color="#007AFF",
alpha=0.07, lw=0)
for sign in (-1, 1):
ax.plot(pooled + sign * 1.96 * s_grid, s_grid, color="#8E8E93", lw=1, ls="--",
label="Pseudo 95% CI\n(pooled ± 1.96 SE)" if sign > 0 else None)
ax.axvline(pooled, color="#007AFF", lw=1.2, label=f"Pooled (fixed effect)\nd = {pooled:.2f}")
ax.axvline(0, color="#C7C7CC", lw=0.8)
ax.plot(b1 + b0 * s_grid, s_grid, color="#FF9500", lw=1.8, ls="--", label="Egger regression line")
ax.scatter(dp, sp, s=40, color="#007AFF", edgecolor="white", lw=0.7, zorder=3,
label=f"Studies ({len(dp)})")
ax.invert_yaxis()
ax.set_ylim(sp.max() * 1.1, 0)
ax.set_xlim(-0.9, 1.4)
ax.set_xlabel("Standardised mean difference in IQ, expectancy vs control (d)")
ax.set_ylabel("Standard error")
ax.grid(axis="y", visible=False)
handles, labels = ax.get_legend_handles_labels()
order = [3, 1, 2, 0]
ax.legend([handles[i] for i in order], [labels[i] for i in order], loc="upper left",
bbox_to_anchor=(1.01, 1), fontsize=9, labelspacing=1)
ax.set_title("Small studies report larger effects — " + ("Egger's test flags asymmetry"
if egger.pvalues[0] < 0.05 else "but Egger's test is borderline"), pad=26)
ax.text(0, 1.02, f"Egger's test: intercept = {b0:.2f}, t({egger.df_resid:.0f}) = "
f"{egger.tvalues[0]:.2f}, p = {egger.pvalues[0]:.3f} · k = {len(dp)} teacher-expectancy "
f"studies (Raudenbush, 1984)", transform=ax.transAxes, fontsize=9.5, color="#6E6E73")
plt.show()
Les figures utilisent le style PyStatlas (facultatif) : ajoutez plt.style.use("pystatlas.mplstyle") pour obtenir exactement le même rendu.
Source des données
- Teacher-expectancy experiments (Raudenbush, 1984). Raudenbush, S. W. (1984). Magnitude of teacher expectancy effects on pupil IQ as a function of the credibility of expectancy induction: A synthesis of findings from 18 experiments. Journal of Educational Psychology, 76(1), 85–97. https://doi.org/10.1037/0022-0663.76.1.85
Effect sizes and variances typed in from dat.raudenbush1985 in R's metadat/metafor (Viechtbauer, 2010, Journal of Statistical Software, 36(3), https://doi.org/10.18637/jss.v036.i03); one of the 18 experiments contributes two rows.
Les exemples illustrent des méthodes statistiques. Leurs titres décrivent ce que chaque figure montre dans ces données précises — souvent un échantillon restreint, daté ou partiel —, et non la position de l'auteur sur la question de fond. Pour l'interprétation, le contexte et la qualité des données, reportez-vous aux sources originales citées ici.
Comment citer
PyStatlas est créé et maintenu par Thierry Warin. S'il vous a été utile dans vos travaux, merci de le citer.
Warin, T. (2026). Funnel plot. In PyStatlas: A Python Gallery of Statistical Graphics for the Social Sciences. https://warint.github.io/pystatlas/inference-uncertainty/funnel-plot/
@misc{warin2026statlas,
author = {Warin, Thierry},
title = {PyStatlas: A Python Gallery of Statistical Graphics for the Social Sciences},
year = {2026},
howpublished = {\url{https://warint.github.io/pystatlas/}},
note = {Source code: https://github.com/warint/pystatlas}
}Plus dans Inférence et incertitude
Distribution bootstrap
Corrélation rééchantillonnée avec intervalles de confiance à 95 % par percentiles et BCa.
boot::boot() + boot::boot.ci()Ce que signifie un intervalle de confiance à 95 %
100 enquêtes de 30 personnes tirées parmi 944 répondants de l'ANES ; les IC à 95 % de l'âge moyen qui manquent la vraie valeur sont en rouge.
teaching classic (e.g. TeachingDemos::ci.examp())Courbe de puissance
Puissance d'un test t à deux échantillons selon la taille d'échantillon, pour des effets petits, moyens et grands.
pwr::pwr.t.test() + plot()