-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathANOVA.html
More file actions
1266 lines (1162 loc) · 81.9 KB
/
Copy pathANOVA.html
File metadata and controls
1266 lines (1162 loc) · 81.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="de" data-theme="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>ANOVA — MethodsLab</title>
<script>(function(){var t=localStorage.getItem('ml-theme');if(t)document.documentElement.setAttribute('data-theme',t);})();</script>
<style>
@import url('https://fonts.googleapis.com/css2?family=DM+Mono:ital,wght@0,300;0,400;0,500;1,400&family=Fraunces:ital,opsz,wght@0,9..144,200;0,9..144,300;0,9..144,600;1,9..144,300;1,9..144,400&display=swap');
:root{
--bg:#f0ead8;--paper:#f8f3e8;--ink:#18130e;--ink2:#5a4f42;--ink3:#8a7f72;
--a1:#c94a2a;--a2:#2a6e8a;--a3:#5a8a2a;--a4:#7a3a8a;--a5:#b85c00;--a6:#0e7c7b;
--grid:#ddd5c5;--panel:#e8e0ce;--border:#c8bfaa;
--accent:var(--a2);--topbar-h:54px;--tabbar-h:44px;
}
[data-theme="dark"]{
--bg:#0c0f14;--paper:#111520;--ink:#ece6d8;--ink2:#8a8070;--ink3:#857c68;
--a1:#e8614a;--a2:#4ab0d8;--a3:#80cb52;--a4:#c87ad8;--a5:#e07830;--a6:#2bc7c4;
--grid:#1e242e;--panel:#171d28;--border:#2a3040;
}
*{box-sizing:border-box;margin:0;padding:0}
html{font-size:18px}
body{background:var(--bg);color:var(--ink);font-family:'Fraunces',Georgia,serif;font-size:1rem;min-height:100vh}
#topbar{position:sticky;top:0;z-index:300;background:var(--paper);border-bottom:1px solid var(--grid);
padding:.6rem 1.2rem;display:flex;align-items:center;gap:.8rem}
#topbar h1{font-size:1.05rem;font-weight:300;letter-spacing:-.01em;flex:1}
#topbar h1 em{color:var(--accent);font-style:italic}
.tbtn{font-family:'DM Mono',monospace;font-size:.72rem;padding:.28rem .7rem;border:1.5px solid var(--border);
background:transparent;cursor:pointer;color:var(--ink2);transition:all .15s;letter-spacing:.04em}
.tbtn:hover{background:var(--ink);color:var(--bg)}
.tbtn-red{border-color:var(--a1)!important;color:var(--a1)!important}
.tbtn-red:hover{background:var(--a1)!important;color:var(--bg)!important}
/* ── Tab bar ──────────────────────────────────────────────────────── */
#tab-bar{position:sticky;top:var(--topbar-h);z-index:250;display:flex;background:var(--paper);
border-bottom:1px solid var(--border);overflow-x:auto;height:var(--tabbar-h)}
.mod-tab{background:none;border:none;border-bottom:2px solid transparent;
font-family:'DM Mono',monospace;font-size:.8rem;color:var(--ink3);
padding:0 1.3rem;cursor:pointer;white-space:nowrap;display:flex;align-items:center;gap:.5rem;
transition:color .15s,border-color .15s}
.mod-tab:hover{color:var(--ink)}
.mod-tab.active{color:var(--a2);border-bottom-color:var(--a2)}
.tab-num{font-size:1.7rem;font-weight:600;line-height:1;vertical-align:-.15em}
#app{display:grid;grid-template-columns:270px 1fr;height:calc(100vh - var(--topbar-h) - var(--tabbar-h));overflow:hidden}
#sidebar{overflow-y:scroll;height:100%;background:var(--paper);border-right:1px solid var(--grid);padding:1rem .9rem}
#sidebar::-webkit-scrollbar{width:5px}
#sidebar::-webkit-scrollbar-thumb{background:var(--border);border-radius:3px}
#main{overflow-y:scroll;height:100%;padding:1.2rem 1.5rem 3rem}
.mod-panel{display:none}
.mod-panel.active{display:block}
.mod-h{font-size:1.3rem;font-weight:300;letter-spacing:-.01em;margin-bottom:.25rem}
.mod-h em{font-style:italic;color:var(--a2)}
.mod-sub{font-family:'DM Mono',monospace;font-size:.78rem;color:var(--ink3);margin-bottom:1.1rem}
.scard{background:var(--panel);border:1px solid var(--grid);padding:.75rem .85rem;margin-bottom:.7rem}
.scard-title{font-family:'DM Mono',monospace;font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;
color:var(--accent);margin-bottom:.6rem;padding-bottom:.3rem;border-bottom:1px solid var(--grid)}
.sb-stat{font-family:'DM Mono',monospace;font-size:.78rem;line-height:1.9;color:var(--ink2)}
.sb-stat b{color:var(--ink)}
.sb-note{font-size:.82rem;line-height:1.65;color:var(--ink2)}
.sec-h{font-family:'DM Mono',monospace;font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;
color:var(--ink3);margin:1.7rem 0 .6rem;padding-bottom:.3rem;border-bottom:1px solid var(--grid)}
.sec-h:first-child{margin-top:0}
.circ{font-size:2em;font-weight:600;vertical-align:-.18em;line-height:1;display:inline-block}
.gk{font-family:'Fraunces',Georgia,serif;font-style:italic;text-transform:none}
.p-intro{font-size:.92rem;line-height:1.85;color:var(--ink2);margin-bottom:.75rem}
.p-intro strong{color:var(--ink)}
.example-box{background:var(--panel);border-left:3px solid var(--a2);padding:.85rem 1rem;
margin-bottom:.9rem;font-size:.88rem;line-height:1.75}
.example-box strong{color:var(--a2)}
.tutorial-box{background:var(--panel);border-left:3px solid var(--a4);padding:.85rem 1rem;
margin-bottom:.9rem;font-size:.88rem;line-height:1.75}
.tutorial-box strong{color:var(--a4)}
.slider-row{margin-bottom:.55rem}
.slider-lbl{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:.18rem}
.slider-name{font-family:'DM Mono',monospace;font-size:.8rem;color:var(--ink)}
.slider-val{font-family:'DM Mono',monospace;font-size:.82rem;color:var(--accent);font-weight:500}
input[type=range]{width:100%;appearance:none;height:3px;background:var(--grid);border-radius:2px;outline:none;cursor:pointer}
input[type=range]::-webkit-slider-thumb{appearance:none;width:11px;height:11px;background:var(--ink);border-radius:50%;cursor:pointer}
input[type=range]::-webkit-slider-thumb:hover{background:var(--accent)}
input[type=range]::-moz-range-thumb{width:11px;height:11px;background:var(--ink);border-radius:50%;cursor:pointer;border:none}
.seed-btn{font-family:'DM Mono',monospace;font-size:.76rem;padding:.32rem .6rem;
border:1px solid var(--border);background:transparent;cursor:pointer;color:var(--ink2);
transition:all .12s;width:100%;text-align:left;margin-top:.4rem}
.seed-btn:hover{border-color:var(--accent);color:var(--accent)}
.toggle-row{display:flex;align-items:center;gap:.6rem;margin-bottom:.4rem}
.toggle-row label{font-family:'DM Mono',monospace;font-size:.78rem;color:var(--ink2);cursor:pointer}
.radio-row{display:flex;align-items:center;gap:.5rem;margin-bottom:.3rem}
.radio-row label{font-family:'DM Mono',monospace;font-size:.78rem;color:var(--ink2);cursor:pointer}
input[type=checkbox]{width:14px;height:14px;cursor:pointer;accent-color:var(--accent);flex-shrink:0}
input[type=radio]{width:13px;height:13px;cursor:pointer;accent-color:var(--accent);flex-shrink:0}
.swatch{width:11px;height:11px;display:inline-block;border-radius:2px;flex-shrink:0}
.pp-grid{display:grid;grid-template-columns:auto 1fr 1fr;gap:.35rem .55rem;align-items:end;margin-bottom:.65rem}
.pp-colhead{font-family:'DM Mono',monospace;font-size:.66rem;letter-spacing:.04em;color:var(--ink3);
text-align:center;padding-bottom:.2rem;border-bottom:1px solid var(--grid)}
.pp-rowhead{font-family:'DM Mono',monospace;font-size:.72rem;color:var(--ink2);white-space:nowrap;padding-right:.15rem}
.pp-cell{display:flex;flex-direction:column;gap:.2rem}
.pp-cell .slider-val{font-family:'DM Mono',monospace;font-size:.74rem;color:var(--accent);font-weight:500;text-align:center}
.btn-row{display:flex;gap:.5rem;flex-wrap:wrap;margin:.7rem 0}
.canvas-wrap{background:var(--panel);border:1px solid var(--grid);margin-bottom:.6rem;overflow:hidden}
.canvas-wrap canvas{width:100%;display:block}
.canvas-axis-note{font-family:'DM Mono',monospace;font-size:.72rem;color:var(--ink3);
padding:.5rem .85rem;border-top:1px solid var(--grid);line-height:1.5}
.live-readout{background:var(--panel);border:1px solid var(--grid);border-left:3px solid var(--a5);
padding:.7rem .9rem;margin-bottom:.9rem;font-family:'DM Mono',monospace;font-size:.83rem;line-height:1.7;color:var(--ink)}
.live-readout .big{font-size:1.05rem;font-weight:500}
.step-block{margin-bottom:1.1rem}
.step-h{font-size:1rem;font-weight:300;margin-bottom:.35rem}
.step-body{font-size:.87rem;line-height:1.8;color:var(--ink2)}
.step-body strong{color:var(--ink)}
.step-body a{color:var(--a2)}
.mini-table{width:100%;border-collapse:collapse;margin-top:.4rem;margin-bottom:.8rem;font-family:'DM Mono',monospace;font-size:.79rem}
.mini-table th{text-align:left;padding:.28rem .5rem;border-bottom:1px solid var(--grid);color:var(--ink3);
font-size:.68rem;letter-spacing:.06em;text-transform:uppercase;background:var(--paper)}
.mini-table th.num{text-align:right}
.mini-table td{padding:.32rem .5rem;border-bottom:1px solid var(--grid);background:var(--paper);transition:background .15s,color .15s}
.mini-table td.num{text-align:right;font-weight:500;color:var(--ink)}
.mini-table tr.hl td{color:var(--accent);font-weight:600}
.mini-table tr.row-between td{color:var(--a3)}
.mini-table tr.row-within td{color:var(--a5)}
.coef-table{width:100%;border-collapse:collapse;font-family:'DM Mono',monospace;font-size:.78rem;margin-bottom:.6rem}
.coef-table th{font-size:.66rem;letter-spacing:.06em;color:var(--ink3);padding:.26rem .45rem;
border-bottom:2px solid var(--grid);text-align:left}
.coef-table td{padding:.3rem .45rem;border-bottom:1px solid var(--grid);vertical-align:middle}
.coef-table td.num{text-align:right;font-weight:600}
.coef-table td.interp{color:var(--ink2);font-size:.71rem;line-height:1.4}
.coef-table th.r{text-align:right}
.two-col{display:grid;grid-template-columns:1fr 1fr;gap:1rem}
@media (max-width:820px){.two-col{grid-template-columns:1fr}}
.col-h{font-family:'DM Mono',monospace;font-size:.72rem;letter-spacing:.08em;text-transform:uppercase;
color:var(--accent);margin-bottom:.4rem}
.compare-box{font-family:'DM Mono',monospace;font-size:.72rem;color:var(--ink3);
background:var(--panel);border:1px solid var(--grid);padding:.5rem .75rem;line-height:2;margin-bottom:.9rem}
.compare-box strong{color:var(--ink)}
.learn-section{margin-top:2.2rem}
.lcard-grid{display:grid;grid-template-columns:1fr 1fr;gap:.7rem}
@media (max-width:820px){.lcard-grid{grid-template-columns:1fr}}
.lcard{background:var(--paper);border:1.5px solid var(--border);padding:.9rem 1rem}
.lcard-h{font-family:'DM Mono',monospace;font-size:.72rem;color:var(--a2);
letter-spacing:.07em;text-transform:uppercase;margin-bottom:.4rem;font-weight:500}
.lcard-body{font-size:.82rem;line-height:1.75;color:var(--ink2)}
.lcard-body strong{color:var(--ink)}
.lcard-body a{color:var(--a2)}
.help-overlay{display:none;position:fixed;inset:0;z-index:500;background:rgba(0,0,0,.82);overflow-y:auto;padding:2rem 1rem}
.help-overlay.open{display:block}
.help-panel{max-width:700px;margin:0 auto;background:var(--paper);border:1px solid var(--border);padding:2rem}
.help-panel h2{font-family:'Fraunces',serif;font-weight:300;font-size:1.2rem;margin-bottom:1.2rem}
.help-h3{font-family:'DM Mono',monospace;font-size:.74rem;letter-spacing:.09em;text-transform:uppercase;
color:var(--a1);margin:1.1rem 0 .35rem}
.help-p{font-size:.85rem;line-height:1.8;color:var(--ink2);margin-bottom:.6rem}
.help-p code{font-family:'DM Mono',monospace;font-size:.8rem;background:var(--panel);padding:.1rem .35rem;color:var(--ink)}
.help-p a{color:var(--a2)}
.help-close{font-family:'DM Mono',monospace;font-size:.74rem;padding:.3rem .8rem;
border:1.5px solid var(--a1);background:transparent;cursor:pointer;color:var(--a1);transition:all .15s}
.help-close:hover{background:var(--a1);color:var(--bg)}
</style>
</head>
<body>
<div id="topbar">
<h1>ANOVA — <em>ein Spezialfall der Regression</em></h1>
<span style="font-family:'DM Mono',monospace;font-size:.7rem;color:var(--ink3);white-space:nowrap">Dr. R. Düsing · Universität Osnabrück</span>
<button class="tbtn tbtn-red" onclick="toggleHelp()">? Hilfe</button>
<button class="tbtn" id="theme-btn" onclick="toggleTheme()">☀ Light</button>
</div>
<div id="tab-bar">
<button class="mod-tab active" data-tab="1" onclick="showTab(1)"><span class="tab-num">①</span> Einfaktoriell</button>
<button class="mod-tab" data-tab="2" onclick="showTab(2)"><span class="tab-num">②</span> Zweifaktoriell</button>
<button class="mod-tab" data-tab="3" onclick="showTab(3)"><span class="tab-num">③</span> Regressions-Brücke</button>
</div>
<!-- HELP OVERLAY -->
<div class="help-overlay" id="help-overlay" onclick="if(event.target===this)toggleHelp()">
<div class="help-panel">
<div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:1.3rem">
<h2>Hilfe — ANOVA</h2>
<button class="help-close" onclick="toggleHelp()">✕ Schließen</button>
</div>
<div class="help-h3">Was ist eine ANOVA?</div>
<p class="help-p">Eine ANOVA (Varianzanalyse) prüft, ob sich die Mittelwerte von <strong style="color:var(--ink)">mehreren Gruppen</strong> unterscheiden — zum Beispiel: Schneiden drei Lerngruppen unterschiedlich gut in einem Test ab, oder sind die Unterschiede, die man in der Stichprobe sieht, einfach nur Zufallsrauschen? Bei nur zwei Gruppen würde ein t-Test reichen. Bei drei oder mehr Gruppen bräuchte man sonst viele einzelne t-Tests (A vs. B, A vs. C, B vs. C, …) — und mit jedem zusätzlichen Test steigt die Chance, rein zufällig irgendwo eine "Signifikanz" zu finden, obwohl in Wirklichkeit gar kein Unterschied besteht. Die ANOVA vergleicht stattdessen alle Gruppen gemeinsam in einem einzigen Test.</p>
<div class="help-h3">Was misst der F-Wert?</div>
<p class="help-p">Stell dir die Mittelwerte der Gruppen auf einem Zahlenstrahl vor. Liegen sie eng beieinander, war der Unterschied vermutlich Zufall. Liegen sie weit auseinander — weiter, als man angesichts der Streuung <em>innerhalb</em> jeder Gruppe erwarten würde — spricht das für einen echten Effekt. Genau das misst der F-Wert: ein Verhältnis aus "wie unterschiedlich sind die Gruppen zueinander" geteilt durch "wie viel Streuung gibt es sowieso schon innerhalb jeder einzelnen Gruppe". Ein großes F heißt: die Unterschiede zwischen den Gruppen sind groß im Vergleich zum normalen Rauschen. Aus F und den Freiheitsgraden (die u. a. von der Zahl der Gruppen und der Stichprobengröße abhängen) berechnet das Tool automatisch den p-Wert — du musst dafür keine Formel im Kopf haben.</p>
<div class="help-h3">Was zeigt dieses Tool?</div>
<p class="help-p">Drei Reiter oben: <strong style="color:var(--ink)">①</strong> die einfaktorielle ANOVA (ein Faktor, mehrere Gruppen), <strong style="color:var(--ink)">②</strong> die zweifaktorielle ANOVA (zwei Faktoren gleichzeitig, inklusive Interaktion), und <strong style="color:var(--ink)">③</strong> eine Regressions-Brücke: sie zeigt an denselben Daten aus ① und ②, dass eine ANOVA im Kern nichts anderes ist als eine Regression, deren Prädiktor kategorial codiert ist (Gruppenzugehörigkeit statt Zahlenwert) — nur mit eigenem Namen und eigener Tabellen-Tradition. Die Regression ist dabei die flexiblere Variante: sie kann kategoriale und kontinuierliche Prädiktoren im selben Modell kombinieren — genau das tut z. B. die ANCOVA, das direkte Analogon zur ANOVA mit einer zusätzlichen kontinuierlichen Kontrollvariable.</p>
<div class="help-h3">Regler in der Seitenleiste</div>
<p class="help-p">Populationsmittelwerte, Streuung und Stichprobengröße stellst du links ein — Ergebnis-Tabelle und Plot reagieren sofort. "Neue Stichprobe ziehen" behält die aktuellen Regler-Einstellungen, zieht aber neues Zufallsrauschen — so siehst du, wie sehr sich die Zahlen von Stichprobe zu Stichprobe zufällig bewegen, obwohl die zugrunde liegende Population dieselbe bleibt.</p>
<div class="help-h3">Y-Achse fixieren</div>
<p class="help-p">Standardmäßig aktiv: die y-Achse behält den Wertebereich, der beim letzten Aktivieren des Hakens galt, statt sich bei jeder Regler-Bewegung neu anzupassen. So siehst du direkt, wie sich z. B. eine größere Streuung (SD) auf die Punktwolke auswirkt — ohne dass der Plot automatisch mitskaliert und den Effekt dabei wieder "wegkorrigiert". Deaktivieren, um wieder automatisch auf die aktuellen Daten zu skalieren.</p>
<div class="help-h3">SAQ-Bereich hervorheben</div>
<p class="help-p">SAQ steht für Summe der (quadrierten) Abweichungen. Quadriert wird deshalb, weil sich positive und negative Abweichungen vom Mittelwert sonst gegenseitig aufheben würden — die reine Summe der Abweichungen ergibt sonst immer ungefähr null. Der Haken blendet die beiden Bausteine dieser Zerlegung farbig ein: <strong style="color:var(--a3)">Zwischen den Gruppen/Zellen</strong> (Abstand Gruppen-/Zellmittelwert zum Gesamtmittelwert) und <strong style="color:var(--a5)">Innerhalb</strong> (Abstand jeder einzelnen Beobachtung zu ihrem Gruppen-/Zellmittelwert). Beide Kästchen sind unabhängig voneinander an- und abschaltbar; die zugehörigen Tabellenzeilen bleiben dauerhaft in derselben Farbe eingefärbt, auch wenn die Grafik selbst nur das gerade angehakte Element zeigt. In der Tabelle werden F und p außerdem <strong style="color:var(--a1)">rot</strong> hervorgehoben, sobald ein Effekt signifikant wird (p < .05).</p>
</div>
</div>
<div id="app">
<div id="sidebar">
<!-- ═══ SIDEBAR: TAB 1 ═══ -->
<div id="side-tab1" class="side-tab">
<div class="scard">
<div class="scard-title">Unsere Studie</div>
<div class="sb-stat">
n = <b id="sb-n">20</b> pro Gruppe<br>
M<sub>Kontrolle</sub> = <b id="sb-m1">100.0</b><br>
M<sub>A</sub> = <b id="sb-m2">107.0</b><br>
M<sub>B</sub> = <b id="sb-m3">114.0</b><br>
<span style="border-top:1px solid var(--grid);display:block;margin-top:.35rem;padding-top:.35rem">
<span id="sb-row1">F(<span id="sb-df1">2,57</span>) = <b id="sb-F1">—</b><br>
p = <b id="sb-p1">—</b></span></span>
</div>
</div>
<div class="scard">
<div class="scard-title">Populationsparameter</div>
<div class="slider-row">
<div class="slider-lbl"><span class="slider-name"><span class="gk">μ</span> Kontrolle</span><span class="slider-val" id="v-m1">100</span></div>
<input type="range" id="sl-m1" min="60" max="140" step="1" value="100" oninput="onParam1Change()">
</div>
<div class="slider-row">
<div class="slider-lbl"><span class="slider-name"><span class="gk">μ</span> Methode A</span><span class="slider-val" id="v-m2">107</span></div>
<input type="range" id="sl-m2" min="60" max="140" step="1" value="107" oninput="onParam1Change()">
</div>
<div class="slider-row">
<div class="slider-lbl"><span class="slider-name"><span class="gk">μ</span> Methode B</span><span class="slider-val" id="v-m3">114</span></div>
<input type="range" id="sl-m3" min="60" max="140" step="1" value="114" oninput="onParam1Change()">
</div>
<div class="slider-row">
<div class="slider-lbl"><span class="slider-name">SD (gepoolt)</span><span class="slider-val" id="v-sd1">12</span></div>
<input type="range" id="sl-sd1" min="4" max="25" step="1" value="12" oninput="onParam1Change()">
</div>
<div class="slider-row">
<div class="slider-lbl"><span class="slider-name">n pro Gruppe</span><span class="slider-val" id="v-n1">20</span></div>
<input type="range" id="sl-n1" min="5" max="50" step="1" value="20" oninput="onParam1Change()">
</div>
<button class="seed-btn" onclick="drawSample1()">🎲 Neue Stichprobe ziehen</button>
</div>
<div class="scard">
<div class="scard-title">Darstellung</div>
<div class="toggle-row">
<input type="checkbox" id="tog-yfix1" checked onchange="onToggleYFix(1)">
<label for="tog-yfix1">Y-Achse fixieren</label>
</div>
<div style="font-family:'DM Mono',monospace;font-size:.68rem;color:var(--ink3);margin:.2rem 0 .55rem">SAQ-Bereich hervorheben (einzeln zuschaltbar):</div>
<div class="toggle-row">
<input type="checkbox" id="ss1-between" onchange="onSSModeChange(1)">
<span class="swatch" style="background:var(--a3)"></span>
<label for="ss1-between">Zwischen den Gruppen</label>
</div>
<div class="toggle-row">
<input type="checkbox" id="ss1-within" onchange="onSSModeChange(1)">
<span class="swatch" style="background:var(--a5)"></span>
<label for="ss1-within">Innerhalb der Gruppen</label>
</div>
</div>
</div>
<!-- ═══ SIDEBAR: TAB 2 ═══ -->
<div id="side-tab2" class="side-tab" style="display:none">
<div class="scard">
<div class="scard-title">Unsere Studie</div>
<div class="sb-stat">
<span id="sb-rowA">F<sub>A</sub> = <b id="sb-FA">—</b>, p = <b id="sb-pA">—</b></span><br>
<span id="sb-rowB">F<sub>B</sub> = <b id="sb-FB">—</b>, p = <b id="sb-pB">—</b></span><br>
<span id="sb-rowAB">F<sub>A×B</sub> = <b id="sb-FAB">—</b>, p = <b id="sb-pAB">—</b></span>
</div>
</div>
<div class="scard">
<div class="scard-title">Populationsparameter</div>
<div style="font-family:'DM Mono',monospace;font-size:.68rem;color:var(--ink3);margin-bottom:.35rem"><span class="gk">μ</span> je Zelle (Faktor A × Faktor B):</div>
<div class="pp-grid">
<div></div>
<div class="pp-colhead">ohne FB</div>
<div class="pp-colhead">mit FB</div>
<div class="pp-rowhead">Klassisch</div>
<div class="pp-cell">
<span class="slider-val" id="v-c11">100</span>
<input type="range" id="sl-c11" min="60" max="140" step="1" value="100" oninput="onParam2Change()">
</div>
<div class="pp-cell">
<span class="slider-val" id="v-c12">108</span>
<input type="range" id="sl-c12" min="60" max="140" step="1" value="108" oninput="onParam2Change()">
</div>
<div class="pp-rowhead">Verteilt</div>
<div class="pp-cell">
<span class="slider-val" id="v-c21">100</span>
<input type="range" id="sl-c21" min="60" max="140" step="1" value="100" oninput="onParam2Change()">
</div>
<div class="pp-cell">
<span class="slider-val" id="v-c22">108</span>
<input type="range" id="sl-c22" min="60" max="140" step="1" value="108" oninput="onParam2Change()">
</div>
</div>
<div class="slider-row">
<div class="slider-lbl"><span class="slider-name">SD (gepoolt)</span><span class="slider-val" id="v-sd2">12</span></div>
<input type="range" id="sl-sd2" min="4" max="25" step="1" value="12" oninput="onParam2Change()">
</div>
<div class="slider-row">
<div class="slider-lbl"><span class="slider-name">n pro Zelle</span><span class="slider-val" id="v-n2">15</span></div>
<input type="range" id="sl-n2" min="5" max="50" step="1" value="15" oninput="onParam2Change()">
</div>
<button class="seed-btn" onclick="drawSample2()">🎲 Neue Stichprobe ziehen</button>
</div>
<div class="scard">
<div class="scard-title">Darstellung</div>
<div class="toggle-row">
<input type="checkbox" id="tog-yfix2" checked onchange="onToggleYFix(2)">
<label for="tog-yfix2">Y-Achse fixieren</label>
</div>
<div style="font-family:'DM Mono',monospace;font-size:.68rem;color:var(--ink3);margin:.2rem 0 .55rem">SAQ-Bereich hervorheben (einzeln zuschaltbar):</div>
<div class="toggle-row">
<input type="checkbox" id="ss2-between" onchange="onSSModeChange(2)">
<span class="swatch" style="background:var(--a3)"></span>
<label for="ss2-between">Zwischen den Zellen</label>
</div>
<div class="toggle-row">
<input type="checkbox" id="ss2-within" onchange="onSSModeChange(2)">
<span class="swatch" style="background:var(--a5)"></span>
<label for="ss2-within">Innerhalb der Zellen</label>
</div>
</div>
</div>
<!-- ═══ SIDEBAR: TAB 3 ═══ -->
<div id="side-tab3" class="side-tab" style="display:none">
<div class="scard">
<div class="scard-title">Kernaussage</div>
<div class="sb-note">ANOVA und Regression sind <strong style="color:var(--ink)">dasselbe lineare Modell</strong> — nur die Codierung der Gruppenprädiktoren unterscheidet sich. Dummy- und Effekt-Codierung liefern exakt dieselben F- und p-Werte.</div>
</div>
<div class="scard">
<div class="scard-title">Hinweis</div>
<div class="sb-note">Diese Analyse nutzt die aktuellen Stichproben aus ① und ②. Regler zum Ändern findest du auf den jeweiligen Reitern.</div>
</div>
</div>
</div><!-- /sidebar -->
<div id="main">
<!-- ═══════════════════════════════════════════════════════════════
PANEL 1 — EINFAKTORIELLE ANOVA
═══════════════════════════════════════════════════════════════ -->
<div id="panel-tab1" class="mod-panel active">
<div class="mod-h">Einfaktorielle ANOVA: Varianz zerlegen</div>
<div class="mod-sub">Ein Faktor, drei Gruppen — wie viel der Gesamtstreuung erklärt die Gruppenzugehörigkeit?</div>
<div class="example-box">
<strong>Laufendes Beispiel:</strong> Ein Institut für Psychologie testet drei Varianten eines Lernprogramms für den Statistik-Einführungskurs. 60 Studienanfänger:innen werden per Zufallszahlengenerator zu gleichen Teilen (n = 20) auf drei Gruppen verteilt, damit sich Vorwissen und Motivation im Mittel gleichmäßig verteilen und nicht systematisch mit der Gruppe zusammenhängen. <strong>Kontrollgruppe</strong> lernt wie gewohnt mit Skript und Karteikarten in einer Sitzung. <strong>Methode A</strong> verteilt dieselbe Lernzeit über mehrere kürzere Sitzungen auf zwei Wochen (verteiltes Lernen / spaced practice). <strong>Methode B</strong> mischt während des Lernens verschiedene Aufgabentypen, statt sie blockweise abzuarbeiten (Interleaving). Zwei Wochen nach Kursende schreiben alle denselben Gedächtnistest (0–150 Punkte, höher = besser erinnert). Frage: Unterscheiden sich die drei Gruppen im Mittel — und wenn ja, wie stark?
</div>
<div class="step-block">
<div class="step-body">Stell dir die drei Gruppenmittelwerte auf einem Zahlenstrahl vor. Liegen sie eng beieinander, ist der Unterschied vermutlich Zufall (Stichprobenrauschen). Liegen sie weit auseinander — <em>weiter, als man angesichts der Streuung innerhalb jeder Gruppe erwarten würde</em> — spricht das für einen echten Effekt des Faktors. Genau dieses Verhältnis misst der F-Wert: <strong>Varianz zwischen den Gruppen</strong> geteilt durch <strong>Varianz innerhalb der Gruppen</strong>. Links unter "SAQ-Bereich hervorheben" kannst du beide Bausteine einzeln im Plot sichtbar machen — sie sind unabhängig voneinander an- und ausschaltbar.</div>
</div>
<div class="canvas-wrap">
<canvas id="cv1" height="420"></canvas>
</div>
<div class="canvas-axis-note">Punkte = einzelne Beobachtungen (minimal versetzt, damit sie sich nicht überlappen — der x-Wert selbst trägt keine Information) · dicke Linie = Gruppenmittelwert · gestrichelte Linie = Gesamtmittelwert</div>
<div id="anova-table-1"></div>
<div class="live-readout" id="readout1">—</div>
<div class="step-block">
<div class="step-h">Die ANOVA-Tabelle</div>
<div class="step-body">SAQ<sub style="color:var(--a3)">zwischen</sub> misst, wie weit die Gruppenmittelwerte vom Gesamtmittelwert entfernt liegen (gewichtet mit der Gruppengröße). SAQ<sub style="color:var(--a5)">innerhalb</sub> misst die Streuung der einzelnen Beobachtungen um ihren jeweiligen Gruppenmittelwert — das, was ein Gruppenunterschied <em>nicht</em> erklären kann. Division durch die jeweiligen Freiheitsgrade ergibt die mittleren Quadratsummen (MQ); ihr Verhältnis MQ<sub style="color:var(--a3)">zwischen</sub>/MQ<sub style="color:var(--a5)">innerhalb</sub> ist der F-Wert. <span class="gk">η</span>² = SAQ<sub style="color:var(--a3)">zwischen</sub>/SAQ<sub style="color:var(--accent)">total</sub> gibt an, welcher Anteil der Gesamtvarianz durch die Gruppenzugehörigkeit erklärt wird.</div>
</div>
<div class="step-block">
<div class="step-h">Warum reicht der Vergleich der SAQ nicht — wozu die MQ?</div>
<div class="step-body">SAQ<sub style="color:var(--a3)">zwischen</sub> ist eine Summe über <strong>k−1</strong> Termen (hier: 2, einer pro Gruppe minus 1), SAQ<sub style="color:var(--a5)">innerhalb</sub> eine Summe über <strong>N−k</strong> Termen (hier: 57, einer pro Beobachtung minus Gruppenanzahl). Das sind unterschiedlich viele Summanden — und mit jedem zusätzlichen Summanden wächst eine Quadratsumme tendenziell weiter, unabhängig davon, ob überhaupt ein Effekt vorliegt. Ein direkter Vergleich der rohen Summen SAQ<sub style="color:var(--a3)">zwischen</sub> vs. SAQ<sub style="color:var(--a5)">innerhalb</sub> würde also vor allem widerspiegeln, wie viele Freiheitsgrade in jede Summe eingeflossen sind — nicht, wie stark der Gruppenunterschied wirklich ist. Erst die Division durch die jeweiligen df "normiert" beide Summen auf eine <em>durchschnittliche</em> quadrierte Abweichung pro Freiheitsgrad — eine Varianzschätzung. Diese beiden Varianzschätzungen (MQ<sub style="color:var(--a3)">zwischen</sub> und MQ<sub style="color:var(--a5)">innerhalb</sub>) sind unter H₀ (kein echter Effekt) im Erwartungswert gleich groß, was einem F = 1 entspräche (Zähler und Nenner sind gleich groß). Ihr Verhältnis folgt dann einer bekannten Verteilung, der F-Verteilung — das ist die Grundlage für den Signifikanztest. Ohne die Division durch df gäbe es keine Verteilung, gegen die man vergleichen könnte.</div>
</div>
<div class="learn-section">
<div class="sec-h">Konzepte & Einordnung</div>
<div class="lcard-grid">
<div class="lcard">
<div class="lcard-h">"Innerhalb" = Fehlervarianz</div>
<div class="lcard-body">SAQ<sub style="color:var(--a5)">innerhalb</sub> bzw. MQ<sub style="color:var(--a5)">innerhalb</sub> wird in Tabellen und Software meist <strong>MQ<sub style="color:var(--a5)">Fehler</sub></strong> genannt (engl. <em>error</em> oder <em>residual</em>) — dieselbe Größe, anderer Name. Gemeint ist die Streuung, die übrig bleibt, <em>nachdem</em> man die Gruppenzugehörigkeit berücksichtigt hat: individuelle Unterschiede, Messungenauigkeit, alles, was das Modell nicht erklären kann. "Fehler" heißt hier nicht "Messfehler" im engeren Sinn, sondern <strong>unerklärte, als zufällig behandelte Streuung</strong> — der Rest, den die Gruppenzugehörigkeit nicht aufklärt.</div>
</div>
<div class="lcard">
<div class="lcard-h">SAQ und MQ auf einen Blick</div>
<div class="lcard-body">SAQ<sub style="color:var(--a3)">zwischen</sub> + SAQ<sub style="color:var(--a5)">innerhalb</sub> = SAQ<sub style="color:var(--accent)">total</sub> — die Gesamtstreuung zerfällt vollständig in einen erklärten und einen unerklärten Teil. MQ = SAQ/df macht daraus vergleichbare Varianzschätzungen; F = MQ<sub style="color:var(--a3)">zwischen</sub>/MQ<sub style="color:var(--a5)">innerhalb</sub> ist das Verhältnis von erklärter zu unerklärter Varianz pro Freiheitsgrad.</div>
</div>
<div class="lcard">
<div class="lcard-h"><span class="gk">η</span>² als Effektgröße</div>
<div class="lcard-body"><span class="gk">η</span>² = SAQ<sub style="color:var(--a3)">zwischen</sub>/SAQ<sub style="color:var(--accent)">total</sub> beantwortet eine andere Frage als p: nicht "gibt es einen Effekt?", sondern "wie groß ist er, relativ zur Gesamtstreuung?". Ein winziger, aber signifikanter Effekt (großes n) kann ein kleines <span class="gk">η</span>² haben — und umgekehrt. Einordnung neben Cohen's d, r und Odds Ratio: <a href="Effektgroessen.html">→ Effektgrößen</a>.</div>
</div>
<div class="lcard">
<div class="lcard-h">Verwandte Tools</div>
<div class="lcard-body">Dieselbe Analyse als Regression: <a href="#" onclick="showTab(3);return false">→ Tab ③ Regressions-Brücke</a>. Was p wirklich bedeutet: <a href="Signifikanztests.html">→ Signifikanztests</a>. Zwei statt drei Gruppen: ein t-Test ist eine ANOVA mit k=2. Wie groß muss n sein, um einen Effekt zuverlässig zu entdecken? <a href="Power_Stichprobe.html">→ Power & Stichprobengröße</a>.</div>
</div>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════════
PANEL 2 — ZWEIFAKTORIELLE ANOVA
═══════════════════════════════════════════════════════════════ -->
<div id="panel-tab2" class="mod-panel">
<div class="mod-h">Zweifaktorielle ANOVA mit Interaktion</div>
<div class="mod-sub">Zwei Faktoren, vier Zellen — wirkt Faktor A, wirkt Faktor B, und hängt die Wirkung des einen vom anderen ab?</div>
<div class="example-box">
<strong>Eigenständiges Beispiel:</strong> Zur Illustration der Interaktion reduzieren wir hier bewusst auf <strong>zwei</strong> Lernmethoden statt der drei aus Tab ① — Klassisch und Verteiltes Lernen — und kreuzen sie mit einem zweiten Faktor: Feedback (ohne / mit unmittelbarer Rückmeldung nach jeder Lerneinheit). Vier Zellen, balanciertes Design (gleiche Zellgröße n pro Zelle). Die Populationswerte hier sind unabhängig von Tab ① gewählt — beide Tabs lassen sich unabhängig voneinander bedienen.
</div>
<div class="step-block">
<div class="step-h">Was bedeutet eine Interaktion überhaupt?</div>
<div class="step-body">Neben den beiden <strong>Haupteffekten</strong> (Wirkt A im Mittel über beide B-Stufen? Wirkt B im Mittel über beide A-Stufen?) interessiert die <strong>Interaktion</strong>: weicht die Wirkung der Kombination aus Methode und Feedback von dem ab, was die Summe der beiden Haupteffekte vorhersagen würde? Ohne Interaktion sind die Effekte <strong>additiv</strong> — der Feedback-Effekt ist für beide Methoden gleich groß, man kann ihn einfach zum Haupteffekt der Methode dazuzählen. Mit Interaktion lässt sich das nicht mehr trennen: die Wirkung von Feedback unterscheidet sich je nach Methode, und man muss die vier Zellmittelwerte einzeln betrachten, um zu verstehen, was passiert.</div>
</div>
<div class="two-col">
<div>
<div class="col-h">Additiv — keine Interaktion</div>
<table class="mini-table">
<thead><tr><th></th><th class="num">ohne FB</th><th class="num">mit FB</th></tr></thead>
<tbody>
<tr><td>Klassisch</td><td class="num">100</td><td class="num">108</td></tr>
<tr><td>Verteilt</td><td class="num">100</td><td class="num">108</td></tr>
</tbody>
</table>
<div class="sb-note" style="font-size:.8rem">Feedback-Effekt = +8, bei beiden Methoden identisch → im Plot zwei <strong style="color:var(--ink)">parallele</strong> Linien.</div>
</div>
<div>
<div class="col-h">Mit Interaktion</div>
<table class="mini-table">
<thead><tr><th></th><th class="num">ohne FB</th><th class="num">mit FB</th></tr></thead>
<tbody>
<tr><td>Klassisch</td><td class="num">100</td><td class="num">102</td></tr>
<tr><td>Verteilt</td><td class="num">100</td><td class="num">120</td></tr>
</tbody>
</table>
<div class="sb-note" style="font-size:.8rem">Feedback-Effekt = +2 bei Klassisch, +20 bei Verteilt → im Plot <strong style="color:var(--ink)">unterschiedlich steile</strong>, sich öffnende Linien.</div>
</div>
</div>
<div class="step-block">
<div class="step-body">Wenn sich die Linien dabei sogar <em>kreuzen</em> (Feedback hilft bei einer Methode, schadet aber bei der anderen), spricht man von einer <strong>disordinalen</strong> Interaktion — die Richtung des Effekts kehrt sich um. Öffnen sich die Linien nur unterschiedlich stark, ohne sich zu kreuzen (wie im Beispiel rechts oben), ist es eine <strong>ordinale</strong> Interaktion — die Richtung bleibt gleich, nur die Stärke unterscheidet sich. Beide Formen sind statistisch "Interaktion", aber inhaltlich sehr unterschiedlich zu interpretieren.</div>
</div>
<div class="tutorial-box">
<strong>Tutorial — probier's aus:</strong> Die Regler links sind so voreingestellt, dass <strong>nur</strong> ein Haupteffekt von Feedback existiert (mit FB liegt für beide Methoden gleichermaßen höher), aber <strong>kein</strong> Haupteffekt der Lernmethode und <strong>keine</strong> Interaktion. Ändere jetzt gezielt <strong>genau eine</strong> Zelle — z. B. im 2×2-Regler-Raster links unten rechts (Zeile "Verteilt", Spalte "mit FB") deutlich nach oben. Beobachte: Die <strong>Interaktion</strong> wird signifikant (die F/p-Werte in der Tabelle unten färben sich rot), während der Haupteffekt der Lernmethode oft weiterhin <em>nicht</em> signifikant bleibt — weil Haupteffekte über die jeweils andere Faktorstufe <em>mitteln</em>, und sich eine Veränderung in nur einer Zelle in diesem Mittel teilweise wegkürzt, obwohl sie lokal sehr wohl einen Unterschied macht.
</div>
<div class="canvas-wrap">
<canvas id="cv2" height="440"></canvas>
</div>
<div class="canvas-axis-note">x-Achse: Faktor A (Lernmethode) · Linienfarbe: Faktor B (Feedback) · kleine Punkte = einzelne Beobachtungen · Fehlerbalken: ±1 SE</div>
<div id="anova-table-2"></div>
<div class="live-readout" id="readout3">—</div>
<div class="step-block">
<div class="step-h">Warum das nur bei balancierten Designs so glatt aufgeht</div>
<div class="step-body">Bei gleicher Zellgröße n sind die drei Effekte (A, B, Interaktion) statistisch unabhängig voneinander — deshalb lässt sich jeder für sich betrachten, ohne die anderen "herauszurechnen". Bei <strong>unbalancierten</strong> Zellgrößen gilt das nicht mehr — mehr dazu in Tab ③ und den Konzeptkarten dort. Kontinuierliche statt kategoriale Interaktionen behandelt <a href="Moderationsanalyse.html">→ Moderationsanalyse</a>.</div>
</div>
<div class="learn-section">
<div class="sec-h">Konzepte & Einordnung</div>
<div class="lcard-grid">
<div class="lcard">
<div class="lcard-h">"Innerhalb der Zellen" = Fehlervarianz</div>
<div class="lcard-body">Genau wie in Tab ① heißt SAQ<sub style="color:var(--a5)">innerhalb</sub>/MQ<sub style="color:var(--a5)">innerhalb</sub> in Tabellen oft <strong>MQ<sub style="color:var(--a5)">Fehler</sub></strong> — die Streuung <em>innerhalb</em> der vier Zellen, gepoolt über alle vier. Sie bleibt dieselbe Rolle spielen, egal ob ein oder zwei Faktoren im Modell stehen: das, was nach Berücksichtigung aller Zellzugehörigkeiten an Streuung übrig bleibt und als zufällig behandelt wird. Alle drei F-Tests (A, B, Interaktion) teilen sich dasselbe MQ<sub style="color:var(--a5)">Fehler</sub> im Nenner.</div>
</div>
<div class="lcard">
<div class="lcard-h">Haupteffekt vs. Interaktion</div>
<div class="lcard-body">Ein Haupteffekt ist ein <strong>Mittelwert über die Stufen des jeweils anderen Faktors</strong> — er kann täuschen, wenn eine Interaktion vorliegt (siehe Tutorial oben: nur eine Zelle verändert sich, aber die gemittelten Haupteffekte bleiben unauffällig). Deshalb gilt als Faustregel: <strong>immer zuerst die Interaktion prüfen</strong>. Ist sie signifikant, sind Haupteffekte allein oft nicht mehr aussagekräftig interpretierbar — dann lohnt der Blick auf die einzelnen Zellmittelwerte statt auf die Randmittelwerte.</div>
</div>
<div class="lcard">
<div class="lcard-h">Ordinal vs. disordinal</div>
<div class="lcard-body">Bei einer <strong>ordinalen</strong> Interaktion bleibt die Rangfolge der Stufen über den anderen Faktor hinweg gleich — nur der Abstand ändert sich (Linien öffnen sich, kreuzen sich aber nicht). Bei einer <strong>disordinalen</strong> (Crossover-)Interaktion kehrt sich die Richtung um — was auf einer Stufe hilft, schadet auf der anderen. Disordinale Interaktionen sind praktisch meist die interessanteren, weil sie bedeuten: es gibt keine pauschal "beste" Stufe, es kommt darauf an.</div>
</div>
<div class="lcard">
<div class="lcard-h">Verwandte Tools</div>
<div class="lcard-body">Dieselbe Analyse als Regression mit Produktterm: <a href="#" onclick="showTab(3);return false">→ Tab ③ Regressions-Brücke</a>. Kontinuierliche statt kategoriale Interaktionen (z. B. Alter statt Lernmethode): <a href="Moderationsanalyse.html">→ Moderationsanalyse</a>. Faktoren mit zufälligen statt festen Stufen (z. B. Schulklassen): <a href="MLM_interactive.html">→ Multilevel-Modelle</a>.</div>
</div>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════════
PANEL 3 — REGRESSIONS-BRÜCKE
═══════════════════════════════════════════════════════════════ -->
<div id="panel-tab3" class="mod-panel">
<div class="mod-h">Regressions-Brücke: dieselbe Analyse, andere Codierung</div>
<div class="mod-sub">Genau dieselben Stichproben aus ① und ②, noch einmal als multiple Regression gerechnet.</div>
<div class="p-intro">
Eine ANOVA <strong>ist</strong> eine multiple Regression, deren kategorialer Prädiktor auf eine bestimmte Weise numerisch codiert wurde. Das lässt sich direkt nachrechnen: dieselben Rohdaten, einmal mit der klassischen ANOVA-Formel analysiert (Tabs ① und ②), einmal als Regression mit codierten Gruppenprädiktoren — und beide liefern exakt dieselben F- und p-Werte.
</div>
<div class="sec-h">Einfaktoriell: Dummy- vs. Effekt-Codierung</div>
<div class="step-block">
<div class="step-body">Zwei gängige Codierschemata im direkten Vergleich: <strong style="color:var(--ink)">Dummy-Codierung</strong> (eine Referenzgruppe, Koeffizienten = Mittelwertsdifferenzen zur Referenz) und <strong style="color:var(--ink)">Effekt-Codierung</strong> (Summe-Null-Kontraste, Koeffizienten = Abweichungen vom Gesamtmittelwert). Beide Modelle haben drei freie Parameter für drei Gruppen — sie sind "gesättigt" und reproduzieren die drei Gruppenmittelwerte aus Tab ① exakt, unabhängig von der Codierung.</div>
</div>
<div class="two-col">
<div>
<div class="col-h">Dummy-Codierung (Referenz: Kontrolle)</div>
<div id="coef-dummy"></div>
</div>
<div>
<div class="col-h">Effekt-Codierung (Summe-Null-Kontraste)</div>
<div id="coef-effect"></div>
</div>
</div>
<div class="live-readout" id="readout2">—</div>
<div class="step-block">
<div class="step-h">Eine Parametrisierung, keine zwei Verfahren</div>
<div class="step-body">F, p, R² und die vorhergesagten Gruppenmittelwerte sind in beiden Codierungen identisch — nur die Bedeutung der einzelnen Koeffizienten ändert sich. R² dieser Regression ist übrigens identisch mit <span class="gk">η</span>² aus Tab ①: dieselbe Größe, zweimal berechnet.</div>
</div>
<div class="sec-h">Zweifaktoriell: Effekt-Codierung + Produktterm (Typ-III-Quadratsummen)</div>
<div class="step-block">
<div class="step-body">Die Regression codiert A und B als ±1-Kontraste und bildet die Interaktion als Produktterm X<sub>A</sub>·X<sub>B</sub>. Bei einem balancierten 2×2-Design (gleiche Zellgröße n) stehen alle drei Kontrastspalten wechselseitig senkrecht aufeinander (unkorreliert) — deshalb liefert das Herausnehmen je einer Spalte aus dem vollen Modell (die "Typ-III-Quadratsumme") exakt dieselbe SAQ wie die klassische Formel aus Tab ②.</div>
</div>
<div id="coef-twoway"></div>
<div id="compare-twoway"></div>
<div class="step-block">
<div class="step-body">Bei <strong>unbalancierten</strong> Zellgrößen gilt die Orthogonalität nicht mehr — dann unterscheiden sich Typ-I-, Typ-II- und Typ-III-Quadratsummen, und die Wahl wird zu einer echten Modellierungsentscheidung (siehe Konzeptkarte unten).</div>
</div>
<div class="step-block">
<div class="step-h">Dieselbe Rechnung heißt woanders "Moderationsanalyse"</div>
<div class="step-body">Die Produktterm-Regression oben <strong>ist</strong> eine Moderationsanalyse: X<sub>A</sub>·X<sub>B</sub> ist exakt der Interaktions-/Moderationsterm, und der F-Test darauf beantwortet dieselbe Frage wie in Tab ②: hängt der Effekt von A von der Stufe von B ab (und umgekehrt)? Es ist nicht "ANOVA versus Moderationsanalyse" — es ist <strong>dasselbe Modell mit zwei Vokabularen für dieselben Bausteine</strong>: Faktor A und Faktor B (ANOVA) heißen in der Moderationssprache Prädiktor und Moderator, und die Interaktion A×B heißt dort Interaktionsterm bzw. Moderationseffekt. Ein "Haupteffekt" hat dabei kein eigenes Gegenstück in der Moderationssprache — gemeint ist dort einfach der Effekt von Prädiktor oder Moderator für sich genommen, bei einem festen (meist mittleren) Wert des jeweils anderen. Der praktische Unterschied liegt nur darin, wofür jedes Vokabular typischerweise verwendet wird: die klassische ANOVA-Rechnung setzt kategoriale Faktoren voraus, während die allgemeinere Moderationsanalyse nominale und metrische Prädiktoren beliebig mischen und kombinieren kann — z. B. Lernmethode (kategorial) × Vorwissen-Testscore (metrisch) statt Lernmethode × Feedback-ja/nein. Mehr dazu, inklusive stetiger Moderator-Plots: <a href="Moderationsanalyse.html">→ Moderationsanalyse</a>.</div>
</div>
<!-- Konzepte -->
<div class="learn-section">
<div class="sec-h">Konzepte & Einordnung</div>
<div class="lcard-grid">
<div class="lcard">
<div class="lcard-h">Dummy- vs. Effekt-Codierung</div>
<div class="lcard-body">Dummy-Codierung (R nennt es "treatment contrasts") setzt eine Referenzgruppe; Koeffizienten sind Mittelwertsdifferenzen zu dieser Referenz. Effekt-Codierung (Summe-Null-Kontraste) setzt keinen festen Bezugspunkt; Koeffizienten sind Abweichungen vom Gesamtmittelwert, wie sie SPSS und die meisten ANOVA-Ausgaben implizit verwenden. Beides sind Reparametrisierungen <strong>desselben</strong> Modells — identische Vorhersagen, identisches F, identisches p.</div>
</div>
<div class="lcard">
<div class="lcard-h">SAQ Typ I, II, III</div>
<div class="lcard-body"><strong>Typ I</strong> (sequenziell): jeder Term wird nur unter Kontrolle der zuvor eingegebenen Terme getestet — reihenfolgeabhängig. <strong>Typ II</strong>: jeder Haupteffekt unter Kontrolle aller anderen Haupteffekte, aber ohne Interaktionen höherer Ordnung. <strong>Typ III</strong>: jeder Term unter Kontrolle aller anderen Terme inklusive Interaktionen — das, was die Regression mit Effekt-Codierung liefert. Bei balancierten Designs sind alle drei identisch (Tab ②); bei unbalancierten weichen sie voneinander ab.</div>
</div>
<div class="lcard">
<div class="lcard-h">ANOVA-Tabelle: Anatomie</div>
<div class="lcard-body">SAQ (Summe der Abweichungsquadrate, engl. Sum of Squares) = Streuung in Quadrateinheiten der AV. df = Freiheitsgrade. MQ = SAQ/df, eine Varianzschätzung. F = MQ<sub style="color:var(--a3)">Effekt</sub>/MQ<sub style="color:var(--a5)">Fehler</sub>, verglichen mit der F-Verteilung unter H₀ (kein Effekt). Dieselbe Logik wie der F-Test auf R²-Zuwachs in der Regression — nur mit ANOVA-typischem Vokabular für die Quellen der Varianz.</div>
</div>
<div class="lcard">
<div class="lcard-h"><span class="gk">η</span>² und partielles <span class="gk">η</span>²</div>
<div class="lcard-body"><span class="gk">η</span>² = SAQ<sub style="color:var(--a3)">Effekt</sub>/SAQ<sub style="color:var(--accent)">total</sub>, bei einfaktorieller ANOVA identisch mit R² der äquivalenten Regression. Bei mehrfaktoriellen Designs wird meist <strong>partielles</strong> <span class="gk">η</span>² = SAQ<sub style="color:var(--a3)">Effekt</sub>/(SAQ<sub style="color:var(--a3)">Effekt</sub>+SAQ<sub style="color:var(--a5)">Fehler</sub>) berichtet. Einordnung neben Cohen's d, r und Odds Ratio: <a href="Effektgroessen.html">→ Effektgrößen</a>.</div>
</div>
<div class="lcard">
<div class="lcard-h">Wann ANOVA, wann Regression?</div>
<div class="lcard-body">Es ist keine inhaltliche Entscheidung, sondern eine Frage der Berichtskonvention und Softwaregewohnheit — denn die Verfahren sind ineinander verschachtelte Spezialfälle. Ein t-Test ist eine ANOVA mit nur zwei Gruppen. Eine ANOVA wiederum ist eine Regression mit einem oder mehreren kategorialen Dummy-Prädiktoren. Und eine Regression selbst ist nur ein Spezialfall des allgemeinen linearen Modells (GLM) — das sich, sobald verschachtelte oder wiederholt gemessene Daten dazukommen (z. B. Schulklassen, Messwiederholungen), bis zum gemischten Modell (GLMM) erweitern lässt.</div>
</div>
<div class="lcard">
<div class="lcard-h">Verwandte Tools</div>
<div class="lcard-body">Regressionsgrundlagen: <a href="OLS_Regression.html">→ OLS & Multiple Regression</a>. Kontinuierliche Interaktionen: <a href="Moderationsanalyse.html">→ Moderationsanalyse</a>. Random statt Fixed Effects: <a href="MLM_interactive.html">→ Multilevel-Modelle</a>. Power für Gruppenvergleiche: <a href="Power_Stichprobe.html">→ Power & Stichprobengröße</a>. Was p wirklich bedeutet: <a href="Signifikanztests.html">→ Signifikanztests</a>.</div>
</div>
</div>
</div>
</div>
</div><!-- /main -->
</div><!-- /app -->
<script>
// ─── Tabs ─────────────────────────────────────────────────────────────────────
function showTab(n){
document.querySelectorAll('.mod-tab').forEach(t=>t.classList.toggle('active', t.dataset.tab==String(n)));
document.querySelectorAll('.mod-panel').forEach((p,i)=>p.classList.toggle('active', i===n-1));
document.getElementById('side-tab1').style.display = n===1?'block':'none';
document.getElementById('side-tab2').style.display = n===2?'block':'none';
document.getElementById('side-tab3').style.display = n===3?'block':'none';
document.getElementById('main').scrollTop = 0;
if(n===1) drawCv1();
if(n===2) drawCv2();
}
// ─── Theme ────────────────────────────────────────────────────────────────────
function toggleTheme(){
const d=document.documentElement;
const dark=d.getAttribute('data-theme')==='dark';
const next=dark?'light':'dark';
d.setAttribute('data-theme',next);
localStorage.setItem('ml-theme',next);
document.getElementById('theme-btn').textContent=dark?'🌙 Dark':'☀ Light';
redrawAll();
}
function toggleHelp(){document.getElementById('help-overlay').classList.toggle('open')}
document.addEventListener('keydown',e=>{if(e.key==='Escape')document.getElementById('help-overlay').classList.remove('open')});
// ─── PRNG & math ──────────────────────────────────────────────────────────────
function mulberry32(a){return function(){a|=0;a=a+0x6D2B79F5|0;let t=Math.imul(a^a>>>15,1|a);t=t+Math.imul(t^t>>>7,61|t)^t;return((t^t>>>14)>>>0)/4294967296;};}
let rng=mulberry32(20260818);
function randn(){let u=0,v=0;while(u===0)u=rng();while(v===0)v=rng();return Math.sqrt(-2*Math.log(u))*Math.cos(2*Math.PI*v);}
function lgamma(x){
const c=[76.18009172947146,-86.50532032941677,24.01409824083091,
-1.231739572450155,0.1208650973866179e-2,-0.5395239384953e-5];
let y=x,tmp=x+5.5;
tmp-=(x+.5)*Math.log(tmp);
let s=1.000000000190015;
for(let j=0;j<6;j++) s+=c[j]/++y;
return -tmp+Math.log(2.5066282746310005*s/x);
}
function ibeta(x,a,b){
if(x<=0) return 0;
if(x>=1) return 1;
const lbeta=lgamma(a+b)-lgamma(a)-lgamma(b);
function cf(x,a,b){
const maxit=200,eps=3e-7,fpmin=1e-30;
const qab=a+b,qap=a+1,qam=a-1;
let c=1,d=1-(qab*x/qap);
if(Math.abs(d)<fpmin) d=fpmin; d=1/d;
let h=d;
for(let m=1;m<=maxit;m++){
const m2=2*m;
let aa=m*(b-m)*x/((qam+m2)*(a+m2));
d=1+aa*d; if(Math.abs(d)<fpmin) d=fpmin;
c=1+aa/c; if(Math.abs(c)<fpmin) c=fpmin;
d=1/d; h*=d*c;
aa=-(a+m)*(qab+m)*x/((a+m2)*(qap+m2));
d=1+aa*d; if(Math.abs(d)<fpmin) d=fpmin;
c=1+aa/c; if(Math.abs(c)<fpmin) c=fpmin;
d=1/d; const del=d*c; h*=del;
if(Math.abs(del-1)<eps) break;
}
return h;
}
const bt=Math.exp(lbeta+a*Math.log(x)+b*Math.log(1-x));
if(x<(a+1)/(a+b+2)) return bt*cf(x,a,b)/a;
return 1-bt*cf(1-x,b,a)/b;
}
function fCDF(f,d1,d2){
if(f<=0) return 0;
if(!isFinite(f)) return 1;
const x=d1*f/(d1*f+d2);
return ibeta(x,d1/2,d2/2);
}
function fPValue(f,d1,d2){ return Math.max(0,1-fCDF(f,d1,d2)); }
function fmt(x,d=3){return isNaN(x)||!isFinite(x)?'—':x.toFixed(d)}
function fmtp(p){return isNaN(p)?'—':(p<.001?'<.001':p.toFixed(3))}
function mean(arr){return arr.reduce((s,v)=>s+v,0)/arr.length}
function sd(arr){const m=mean(arr);return Math.sqrt(arr.reduce((s,v)=>s+(v-m)**2,0)/(arr.length-1))}
// deterministic per-index pseudo-jitter in [-0.5,0.5], stable across redraws without new data
function hashJitter(i){const x=Math.sin(i*12.9898+4.1414)*43758.5453; return (x-Math.floor(x))-0.5;}
// ─── Generic OLS engine ─────────────────────────────────────────────────────────
function solveLinear(A,b){
const n=A.length;
const M=A.map((row,i)=>row.concat([b[i]]));
for(let col=0;col<n;col++){
let piv=col;
for(let r=col+1;r<n;r++) if(Math.abs(M[r][col])>Math.abs(M[piv][col])) piv=r;
const tmp=M[col]; M[col]=M[piv]; M[piv]=tmp;
const pv=M[col][col];
if(Math.abs(pv)<1e-12) continue;
for(let c=col;c<=n;c++) M[col][c]/=pv;
for(let r=0;r<n;r++){
if(r===col) continue;
const f=M[r][col];
if(f===0) continue;
for(let c=col;c<=n;c++) M[r][c]-=f*M[col][c];
}
}
return M.map(row=>row[n]);
}
function olsFit(X,y){
const n=X.length, p=X[0].length;
const XtX=Array.from({length:p},()=>new Array(p).fill(0));
const Xty=new Array(p).fill(0);
for(let i=0;i<n;i++){
for(let a=0;a<p;a++){
Xty[a]+=X[i][a]*y[i];
for(let b=0;b<p;b++) XtX[a][b]+=X[i][a]*X[i][b];
}
}
const beta=solveLinear(XtX,Xty);
const fitted=X.map(row=>row.reduce((s,v,idx)=>s+v*beta[idx],0));
const my=mean(y);
let SSE=0,SST=0;
for(let i=0;i<n;i++){ SSE+=(y[i]-fitted[i])**2; SST+=(y[i]-my)**2; }
return {beta,fitted,SSE,SST,SSR:SST-SSE,n,p};
}
function partialSS(X,y,dropIdx,full){
const Xred=X.map(row=>row.filter((_,idx)=>idx!==dropIdx));
const red=olsFit(Xred,y);
return red.SSE-full.SSE;
}
// ─── Colors ───────────────────────────────────────────────────────────────────
function getC(){
const dark=document.documentElement.getAttribute('data-theme')==='dark';
return{
ink: dark?'#ece6d8':'#18130e', ink2: dark?'#8a8070':'#5a4f42', ink3: dark?'#857c68':'#8a7f72',
paper: dark?'#111520':'#f8f3e8', panel: dark?'#171d28':'#e8e0ce', grid: dark?'#1e242e':'#ddd5c5',
a1: dark?'#e8614a':'#c94a2a', a2: dark?'#4ab0d8':'#2a6e8a', a3: dark?'#80cb52':'#5a8a2a',
a4: dark?'#c87ad8':'#7a3a8a', a5: dark?'#e07830':'#b85c00', a6: dark?'#2bc7c4':'#0e7c7b',
};
}
// ═══ SECTION ① — one-way ANOVA ═════════════════════════════════════════════════
const GNAMES1=['Kontrolle','Methode A','Methode B'];
const GCOL1=['a2','a4','a6'];
let data1={groups:[[],[],[]]};
let ST1={fixY:true, fixedYMin:null, fixedYMax:null, showBetween:false, showWithin:false};
function currentParams1(){
return{
mu:[parseFloat(document.getElementById('sl-m1').value),
parseFloat(document.getElementById('sl-m2').value),
parseFloat(document.getElementById('sl-m3').value)],
sd: parseFloat(document.getElementById('sl-sd1').value),
n: parseInt(document.getElementById('sl-n1').value)
};
}
function onParam1Change(){
document.getElementById('v-m1').textContent=document.getElementById('sl-m1').value;
document.getElementById('v-m2').textContent=document.getElementById('sl-m2').value;
document.getElementById('v-m3').textContent=document.getElementById('sl-m3').value;
document.getElementById('v-sd1').textContent=document.getElementById('sl-sd1').value;
document.getElementById('v-n1').textContent=document.getElementById('sl-n1').value;
drawSample1();
}
function onSSModeChange(tab){
if(tab===1){
ST1.showBetween=document.getElementById('ss1-between').checked;
ST1.showWithin=document.getElementById('ss1-within').checked;
drawCv1();
}else{
ST2.showBetween=document.getElementById('ss2-between').checked;
ST2.showWithin=document.getElementById('ss2-within').checked;
drawCv2();
}
}
function onToggleYFix(tab){
if(tab===1){
ST1.fixY=document.getElementById('tog-yfix1').checked;
if(ST1.fixY) captureFixedY1();
drawCv1();
}else{
ST2.fixY=document.getElementById('tog-yfix2').checked;
if(ST2.fixY) captureFixedY2();
drawCv2();
}
}
function captureFixedY1(){
const allVals=data1.groups.flat();
const dataMin=Math.min(...allVals), dataMax=Math.max(...allVals);
const pad=(dataMax-dataMin)*0.15||5;
ST1.fixedYMin=dataMin-pad; ST1.fixedYMax=dataMax+pad;
}
function growFixedY1(){
const allVals=data1.groups.flat();
const dataMin=Math.min(...allVals), dataMax=Math.max(...allVals);
const pad=(dataMax-dataMin)*0.15||5;
const needMin=dataMin-pad, needMax=dataMax+pad;
if(ST1.fixedYMin===null){ ST1.fixedYMin=needMin; ST1.fixedYMax=needMax; }
else{
if(needMin<ST1.fixedYMin) ST1.fixedYMin=needMin;
if(needMax>ST1.fixedYMax) ST1.fixedYMax=needMax;
}
}
// Draws n values ~ N(mu,sd) but shifts them so their empirical mean is exactly mu —
// individual points still scatter with the chosen SD, but the plotted group mean
// (and thus SAQ_zwischen/the ANOVA "signal") always matches the slider value exactly,
// so only SAQ_innerhalb varies between "Neue Stichprobe ziehen" clicks.
function sampleExactMean(mu,sd,n){
const arr=[]; for(let i=0;i<n;i++) arr.push(mu+sd*randn());
const shift=mu-mean(arr);
return arr.map(v=>v+shift);
}
function drawSample1(){
const p=currentParams1();
data1.groups=p.mu.map(m=>sampleExactMean(m,p.sd,p.n));
if(ST1.fixY) growFixedY1();
updateSection1();
}
function anovaOneWay(groups){
const k=groups.length;
const ns=groups.map(g=>g.length);
const N=ns.reduce((a,b)=>a+b,0);
const means=groups.map(mean);
const grand=mean(groups.flat());
const SSb=groups.reduce((s,g,i)=>s+ns[i]*(means[i]-grand)**2,0);
const SSw=groups.reduce((s,g,i)=>s+g.reduce((ss,v)=>ss+(v-means[i])**2,0),0);
const SSt=SSb+SSw;
const dfb=k-1, dfw=N-k;
const MSb=SSb/dfb, MSw=SSw/dfw;
const F=MSb/MSw;
const p=fPValue(F,dfb,dfw);
const eta2=SSb/SSt;
return{k,ns,N,means,grand,SSb,SSw,SSt,dfb,dfw,MSb,MSw,F,p,eta2};
}
let res1=null, resDummy=null, resEffect=null;
function updateSection1(){
res1=anovaOneWay(data1.groups);
const p=currentParams1();
document.getElementById('sb-n').textContent=p.n;
document.getElementById('sb-m1').textContent=fmt(res1.means[0],1);
document.getElementById('sb-m2').textContent=fmt(res1.means[1],1);
document.getElementById('sb-m3').textContent=fmt(res1.means[2],1);
document.getElementById('sb-df1').textContent=res1.dfb+','+res1.dfw;
document.getElementById('sb-F1').textContent=fmt(res1.F,2);
document.getElementById('sb-p1').textContent=fmtp(res1.p);
document.getElementById('sb-row1').style.color=res1.p<.05?'var(--a1)':'';
renderTable1();
const verdict=res1.p<.05?'signifikant':'nicht signifikant';
const mag=res1.eta2<.01?'sehr klein':res1.eta2<.06?'klein':res1.eta2<.14?'mittel':'groß';
document.getElementById('readout1').innerHTML=
'<span class="big">F('+res1.dfb+','+res1.dfw+') = '+fmt(res1.F,2)+'</span> · p = '+fmtp(res1.p)+' — '+verdict+
' (<span class="gk">α</span>=.05) · <span class="gk">η</span>² = '+fmt(res1.eta2,3)+' ('+mag+' nach Cohens Konvention)';
drawCv1();
updateSection2();
}
function renderTable1(){
if(!res1) return;
const sig1=res1.p<.05?' style="color:var(--a1);font-weight:700"':'';
document.getElementById('anova-table-1').innerHTML=
'<table class="mini-table"><thead><tr><th>Quelle</th><th class="num">SAQ</th><th class="num">df</th>'+
'<th class="num">MQ</th><th class="num">F</th><th class="num">p</th></tr></thead><tbody>'+
'<tr class="row-between"><td>Zwischen den Gruppen</td><td class="num">'+fmt(res1.SSb,1)+'</td><td class="num">'+res1.dfb+'</td>'+
'<td class="num">'+fmt(res1.MSb,1)+'</td><td class="num"'+sig1+'>'+fmt(res1.F,2)+'</td><td class="num"'+sig1+'>'+fmtp(res1.p)+'</td></tr>'+
'<tr class="row-within"><td>Innerhalb der Gruppen</td><td class="num">'+fmt(res1.SSw,1)+'</td><td class="num">'+res1.dfw+'</td>'+
'<td class="num">'+fmt(res1.MSw,1)+'</td><td class="num">—</td><td class="num">—</td></tr>'+
'<tr class="hl"><td>Total</td><td class="num">'+fmt(res1.SSt,1)+'</td><td class="num">'+(res1.N-1)+'</td>'+
'<td class="num">—</td><td class="num">—</td><td class="num">—</td></tr>'+
'</tbody></table>';
}
function drawCv1(){
const H=420, cv=document.getElementById('cv1');
const W=cv.offsetWidth||800; cv.width=W; cv.height=H;
const ctx=cv.getContext('2d'); const C=getC();
ctx.fillStyle=C.panel; ctx.fillRect(0,0,W,H);
if(!res1) return;
const padL=72,padR=30,padT=30,padB=50;
const plotW=W-padL-padR, plotH=H-padT-padB, yBase=padT+plotH;
let yMin,yMax;
if(ST1.fixY && ST1.fixedYMin!==null){ yMin=ST1.fixedYMin; yMax=ST1.fixedYMax; }
else{
const allVals=data1.groups.flat();
const dataMin=Math.min(...allVals), dataMax=Math.max(...allVals);
const pad=(dataMax-dataMin)*0.15||5;
yMin=dataMin-pad; yMax=dataMax+pad;
}
const ypx=v=>yBase-(v-yMin)/(yMax-yMin)*plotH;
const k=3, bandW=plotW/k;
const bandCenter=i=>padL+bandW*(i+0.5);
const jitterAmp=Math.min(bandW*0.09, 10);
// SAQ "zwischen" overlay — dimension bracket (grand mean ↔ group mean), left of the point cluster so it never covers data
if(ST1.showBetween){
for(let i=0;i<k;i++){
const x=bandCenter(i)-bandW*0.4;
const yG=ypx(res1.grand), yM=ypx(res1.means[i]);
ctx.strokeStyle=C.a3; ctx.lineWidth=2; ctx.globalAlpha=.95;
ctx.beginPath(); ctx.moveTo(x,yG); ctx.lineTo(x,yM); ctx.stroke();
ctx.beginPath(); ctx.moveTo(x-5,yG); ctx.lineTo(x+5,yG); ctx.stroke();
ctx.beginPath(); ctx.moveTo(x-5,yM); ctx.lineTo(x+5,yM); ctx.stroke();
ctx.globalAlpha=1;
ctx.fillStyle=C.a3; ctx.font='10px DM Mono,monospace'; ctx.textAlign='right';
ctx.fillText((res1.means[i]-res1.grand>=0?'+':'')+fmt(res1.means[i]-res1.grand,1), x-8, (yG+yM)/2+3);
}
}
// SAQ "innerhalb" overlay — thin connector from each point to its group mean, behind the points
if(ST1.showWithin){
ctx.strokeStyle=C.a5; ctx.lineWidth=1.1; ctx.globalAlpha=.55;
for(let i=0;i<k;i++){
const cx=bandCenter(i);
data1.groups[i].forEach((v,j)=>{
const x=cx+hashJitter(j+i*997)*jitterAmp;
ctx.beginPath(); ctx.moveTo(x,ypx(v)); ctx.lineTo(x,ypx(res1.means[i])); ctx.stroke();
});
}
ctx.globalAlpha=1;
}
// grand mean dashed line
ctx.strokeStyle=C.ink3; ctx.lineWidth=1.5; ctx.setLineDash([6,4]);
ctx.beginPath(); ctx.moveTo(padL,ypx(res1.grand)); ctx.lineTo(padL+plotW,ypx(res1.grand)); ctx.stroke();
ctx.setLineDash([]);
ctx.fillStyle=C.ink3; ctx.font='11px DM Mono,monospace'; ctx.textAlign='left';
ctx.fillText('Gesamtmittelwert = '+fmt(res1.grand,1), padL+4, ypx(res1.grand)-6);
// points + group mean lines
for(let i=0;i<k;i++){
const cx=bandCenter(i);
const col=C[GCOL1[i]];
data1.groups[i].forEach((v,j)=>{
const x=cx+hashJitter(j+i*997)*jitterAmp;
ctx.beginPath(); ctx.arc(x,ypx(v),3.6,0,2*Math.PI);
ctx.fillStyle=col; ctx.globalAlpha=.55; ctx.fill(); ctx.globalAlpha=1;
});
ctx.strokeStyle=col; ctx.lineWidth=3;
ctx.beginPath(); ctx.moveTo(cx-bandW*0.3,ypx(res1.means[i])); ctx.lineTo(cx+bandW*0.3,ypx(res1.means[i])); ctx.stroke();
ctx.fillStyle=col; ctx.font='bold 12px DM Mono,monospace'; ctx.textAlign='center';
ctx.fillText(GNAMES1[i], cx, yBase+22);
ctx.font='11px DM Mono,monospace';
ctx.fillText('M='+fmt(res1.means[i],1), cx, yBase+37);
}
// y ticks
ctx.strokeStyle=C.grid; ctx.fillStyle=C.ink3; ctx.font='11px DM Mono,monospace'; ctx.textAlign='right';
const nticks=5;
for(let t=0;t<=nticks;t++){
const v=yMin+(yMax-yMin)*t/nticks;
const py=ypx(v);
ctx.beginPath(); ctx.moveTo(padL-5,py); ctx.lineTo(padL,py); ctx.stroke();
ctx.fillText(v.toFixed(0), padL-9, py+4);
}
ctx.strokeStyle=C.grid; ctx.beginPath(); ctx.moveTo(padL,padT); ctx.lineTo(padL,yBase); ctx.stroke();
// y-axis title (rotated)
ctx.save();
ctx.translate(16,padT+plotH/2); ctx.rotate(-Math.PI/2);
ctx.fillStyle=C.ink3; ctx.font='11px DM Mono,monospace'; ctx.textAlign='center';
ctx.fillText('Gedächtnistest (Punkte)',0,0);
ctx.restore();
}
// ═══ SECTION ③ (data) — regression bridge for one-way ══════════════════════════
function buildDesignDummy(groups){
const X=[],y=[];
groups.forEach((g,gi)=>g.forEach(v=>{ X.push([1, gi===1?1:0, gi===2?1:0]); y.push(v); }));
return{X,y};
}
function buildDesignEffect(groups){
const X=[],y=[];
groups.forEach((g,gi)=>g.forEach(v=>{
let row = gi===0?[1,1,0] : gi===1?[1,0,1] : [1,-1,-1];
X.push(row); y.push(v);
}));
return{X,y};
}
function regF(fit){
const dfr=fit.p-1, dfe=fit.n-fit.p;
const F=(fit.SSR/dfr)/(fit.SSE/dfe);
return{F,dfr,dfe,p:fPValue(F,dfr,dfe),R2:fit.SSR/fit.SST};
}
function updateSection2(){
const {X:Xd,y:yd}=buildDesignDummy(data1.groups);
const {X:Xe,y:ye}=buildDesignEffect(data1.groups);
resDummy=olsFit(Xd,yd);
resEffect=olsFit(Xe,ye);
const fD=regF(resDummy), fE=regF(resEffect);
const p=currentParams1();
const popGrand=(p.mu[0]+p.mu[1]+p.mu[2])/3;
document.getElementById('coef-dummy').innerHTML=
'<table class="coef-table"><tr><th>Parameter</th><th class="r">Populationswert</th><th class="r">Geschätzt</th><th>Interpretation</th></tr>'+
'<tr><td>b₀ (Intercept)</td><td class="num" style="color:var(--ink3)">'+fmt(p.mu[0],2)+'</td><td class="num">'+fmt(resDummy.beta[0],2)+'</td>'+
'<td class="interp">Geschätzter Mittelwert der Referenzgruppe (Kontrolle)</td></tr>'+
'<tr><td>b₁ (D<sub>A</sub>)</td><td class="num" style="color:var(--ink3)">'+fmt(p.mu[1]-p.mu[0],2)+'</td><td class="num">'+fmt(resDummy.beta[1],2)+'</td>'+
'<td class="interp">Differenz Methode A − Kontrolle</td></tr>'+
'<tr><td>b₂ (D<sub>B</sub>)</td><td class="num" style="color:var(--ink3)">'+fmt(p.mu[2]-p.mu[0],2)+'</td><td class="num">'+fmt(resDummy.beta[2],2)+'</td>'+
'<td class="interp">Differenz Methode B − Kontrolle</td></tr></table>';
document.getElementById('coef-effect').innerHTML=
'<table class="coef-table"><tr><th>Parameter</th><th class="r">Populationswert</th><th class="r">Geschätzt</th><th>Interpretation</th></tr>'+
'<tr><td>b₀ (Intercept)</td><td class="num" style="color:var(--ink3)">'+fmt(popGrand,2)+'</td><td class="num">'+fmt(resEffect.beta[0],2)+'</td>'+
'<td class="interp">Gesamtmittelwert (Durchschnitt der 3 Gruppenmittelwerte)</td></tr>'+
'<tr><td>b₁ (E₁)</td><td class="num" style="color:var(--ink3)">'+fmt(p.mu[0]-popGrand,2)+'</td><td class="num">'+fmt(resEffect.beta[1],2)+'</td>'+
'<td class="interp">Abweichung Kontrolle − Gesamtmittelwert</td></tr>'+
'<tr><td>b₂ (E₂)</td><td class="num" style="color:var(--ink3)">'+fmt(p.mu[1]-popGrand,2)+'</td><td class="num">'+fmt(resEffect.beta[2],2)+'</td>'+
'<td class="interp">Abweichung Methode A − Gesamtmittelwert</td></tr>'+
'<tr><td>(implizit) −(b₁+b₂)</td><td class="num" style="color:var(--ink3)">'+fmt(p.mu[2]-popGrand,2)+'</td><td class="num">'+fmt(-(resEffect.beta[1]+resEffect.beta[2]),2)+'</td>'+
'<td class="interp">Abweichung Methode B − Gesamtmittelwert (nicht direkt geschätzt)</td></tr></table>';
document.getElementById('readout2').innerHTML=
'<span class="big">F<sub>Dummy</sub>('+fD.dfr+','+fD.dfe+') = '+fmt(fD.F,2)+'</span>, p = '+fmtp(fD.p)+
' · <span class="big">F<sub>Effekt</sub>('+fE.dfr+','+fE.dfe+') = '+fmt(fE.F,2)+'</span>, p = '+fmtp(fE.p)+
' · beide ≡ F<sub>ANOVA</sub> = '+fmt(res1.F,2)+' aus Tab ① · R² = '+fmt(fD.R2,3)+' = <span class="gk">η</span>² = '+fmt(res1.eta2,3);
}
// ═══ SECTION ② — two-way ANOVA with interaction ════════════════════════════════
const ANAMES=['Klassisch','Verteilt'], BNAMES=['ohne Feedback','mit Feedback'];
let data2={cells:[[[],[]],[[],[]]]};
let ST2={fixY:true, fixedYMin:null, fixedYMax:null, showBetween:false, showWithin:false};