Netzwerkanalyse erweitert:
- 3D-Visualisierung mit Effekt-Achse (z-Modi: Effekt, System, Semantik) - Top-Listen (je 15 positive/negative Effektstärken) ergänzt - Item-Projektion mit Community-Labels - Config um Toggle für z-Modi mit sprechenden Achsentiteln erweitert - Keys konsistent (top_n_extremes, show_item_projection)
This commit is contained in:
@ -1,22 +1,3 @@
|
|||||||
"""
|
|
||||||
Konfiguration Visible Learning
|
|
||||||
|
|
||||||
Diese Datei steuert die Analysen der Effektstärken aus Hattie (Visible Learning).
|
|
||||||
|
|
||||||
- csv_file: Pfad zur Eingabedatei (eine CSV, die alle Kapitel enthalten kann).
|
|
||||||
- k_clusters: Anzahl der Cluster für K-Means.
|
|
||||||
|
|
||||||
- export_fig_visual: True = HTML-Export der Plots.
|
|
||||||
- export_fig_png: True = PNG-Export der Plots (setzt Kaleido voraus).
|
|
||||||
|
|
||||||
- theme: Darstellungs-Theme ("dark" oder "light").
|
|
||||||
|
|
||||||
Kapitelsteuerung:
|
|
||||||
- selected_kapitel: Nummer eines Kapitels (z. B. 5), das isoliert betrachtet werden soll.
|
|
||||||
None = kein Filter, d. h. gesamte CSV in einem Schwung analysieren.
|
|
||||||
- analyse_all: True = alle Kapitel sequenziell einzeln durchlaufen und auswerten.
|
|
||||||
False = nur den Filter aus selected_kapitel beachten.
|
|
||||||
"""
|
|
||||||
# config_visible-learning.py
|
# config_visible-learning.py
|
||||||
|
|
||||||
# Pfad zur Eingabedatei
|
# Pfad zur Eingabedatei
|
||||||
@ -36,3 +17,28 @@ theme = "dark"
|
|||||||
selected_kapitel = None # Nummer des Kapitels (z.B. 5), None = kein Filter
|
selected_kapitel = None # Nummer des Kapitels (z.B. 5), None = kein Filter
|
||||||
analyse_all = False # True = alle Kapitel durchlaufen
|
analyse_all = False # True = alle Kapitel durchlaufen
|
||||||
export_werte_all = True # Wertedatei (werte_all.json) exportieren
|
export_werte_all = True # Wertedatei (werte_all.json) exportieren
|
||||||
|
|
||||||
|
# 3D-Visualisierung: Toggle für die drei z-Modi mit sprechenden Achsentiteln
|
||||||
|
z_mode = "effekt" # Mögliche Werte: "effekt", "kapitel", "system"
|
||||||
|
|
||||||
|
z_axis_labels = {
|
||||||
|
"effekt": "Effektstärke (Cohen d)",
|
||||||
|
"kapitel": "Kapitelnummer",
|
||||||
|
"system": "Systemebene (psychisch/sozial)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ———————————————————————————————————————————————
|
||||||
|
# Zusatz-Ausgaben & Netzwerkanalyse-Optionen
|
||||||
|
# ———————————————————————————————————————————————
|
||||||
|
# 1) Top-Listen der Effektstärken
|
||||||
|
export_top_extremes = True
|
||||||
|
top_n_extremes = 15
|
||||||
|
|
||||||
|
# 2) Item-Projektion im Netzwerk + Community-Labels
|
||||||
|
show_item_projection = True # statt enable_item_projection
|
||||||
|
projection_method = "layout_spring" # "layout_spring" | "umap"
|
||||||
|
show_community_labels = True
|
||||||
|
community_algorithm = "louvain" # "louvain" | "leiden" (falls unterstützt)
|
||||||
|
min_community_size = 3
|
||||||
|
|
||||||
|
# 3) z-Achsen-Toggle kommt aus z_mode / z_axis_labels (oben)
|
||||||
@ -1,4 +1,255 @@
|
|||||||
{
|
{
|
||||||
|
"extremes": {
|
||||||
|
"top_positive": [
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 9.08,
|
||||||
|
"Stichwort": "Kollektive Wirksamkeitserwartung",
|
||||||
|
"Kapitelname": "Lehrperson",
|
||||||
|
"Subkapitel": "Einflüsse der Lehrperson",
|
||||||
|
"Effektstärke": 1.34,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 9.05,
|
||||||
|
"Stichwort": "Einschätzung des Leistungsniveaus durch die Lehrperson",
|
||||||
|
"Kapitelname": "Lehrperson",
|
||||||
|
"Subkapitel": "Einflüsse der Lehrperson",
|
||||||
|
"Effektstärke": 1.3,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.05,
|
||||||
|
"Stichwort": "Erkenntnisstufen",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Fähigkeiten",
|
||||||
|
"Effektstärke": 1.28,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 9.06,
|
||||||
|
"Stichwort": "Glaubwürdigkeit",
|
||||||
|
"Kapitelname": "Lehrperson",
|
||||||
|
"Subkapitel": "Einflüsse der Lehrperson",
|
||||||
|
"Effektstärke": 1.09,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 9.13,
|
||||||
|
"Stichwort": "Micro-Teaching",
|
||||||
|
"Kapitelname": "Lehrperson",
|
||||||
|
"Subkapitel": "Entwicklung von Lehrerprofessionalität",
|
||||||
|
"Effektstärke": 1.01,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 10.3,
|
||||||
|
"Stichwort": "Ergebnisorientierte Bildung",
|
||||||
|
"Kapitelname": "Curriculum",
|
||||||
|
"Subkapitel": "Andere Lehrplanbereiche",
|
||||||
|
"Effektstärke": 0.97,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.01,
|
||||||
|
"Stichwort": "Vorausgehende Fähigkeiten & Intelligenz",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Fähigkeiten",
|
||||||
|
"Effektstärke": 0.96,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.11,
|
||||||
|
"Stichwort": "Beurteilung der eigenen Leistungsfähigkeit",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Fähigkeiten",
|
||||||
|
"Effektstärke": 0.96,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.1,
|
||||||
|
"Stichwort": "Feldunabhängigkeit",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Fähigkeiten",
|
||||||
|
"Effektstärke": 0.94,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 9.07,
|
||||||
|
"Stichwort": "Klarheit der Lehrperson",
|
||||||
|
"Kapitelname": "Lehrperson",
|
||||||
|
"Subkapitel": "Einflüsse der Lehrperson",
|
||||||
|
"Effektstärke": 0.85,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.13,
|
||||||
|
"Stichwort": "Kritisches Denken",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Fähigkeiten",
|
||||||
|
"Effektstärke": 0.84,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 8.13,
|
||||||
|
"Stichwort": "Reduktion von Unterrichtsstörungen",
|
||||||
|
"Kapitelname": "Klassenzimmer",
|
||||||
|
"Subkapitel": "Einflüsse im Klassenzimmer",
|
||||||
|
"Effektstärke": 0.82,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 10.02,
|
||||||
|
"Stichwort": "Leseförderung für besondere Gruppen",
|
||||||
|
"Kapitelname": "Curriculum",
|
||||||
|
"Subkapitel": "Curriculare Programme (Lesen)",
|
||||||
|
"Effektstärke": 0.82,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 10.11,
|
||||||
|
"Stichwort": "Wiederholtes Lesen",
|
||||||
|
"Kapitelname": "Curriculum",
|
||||||
|
"Subkapitel": "Curriculare Programme (Lesen)",
|
||||||
|
"Effektstärke": 0.8,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 10.07,
|
||||||
|
"Stichwort": "Phonologische Bewusstheit",
|
||||||
|
"Kapitelname": "Curriculum",
|
||||||
|
"Subkapitel": "Curriculare Programme (Lesen)",
|
||||||
|
"Effektstärke": 0.75,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"top_negative": [
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.33,
|
||||||
|
"Stichwort": "negativ-aktivierend (Wut)",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Wille",
|
||||||
|
"Effektstärke": -0.65,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.43,
|
||||||
|
"Stichwort": "Misshandlung",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Thrill: Motivation",
|
||||||
|
"Effektstärke": -0.63,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.39,
|
||||||
|
"Stichwort": "Frühgeburt / Geburtsgewicht",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Thrill: Motivation",
|
||||||
|
"Effektstärke": -0.59,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.41,
|
||||||
|
"Stichwort": "Krankheit",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Thrill: Motivation",
|
||||||
|
"Effektstärke": -0.51,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.36,
|
||||||
|
"Stichwort": "negativ-aktivierend (Langeweile)",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Wille",
|
||||||
|
"Effektstärke": -0.46,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.42,
|
||||||
|
"Stichwort": "Körperliche Syndrome",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Thrill: Motivation",
|
||||||
|
"Effektstärke": -0.42,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.38,
|
||||||
|
"Stichwort": "kognitive Dispositionen (Prokrastination)",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Wille",
|
||||||
|
"Effektstärke": -0.41,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.31,
|
||||||
|
"Stichwort": "negativ-aktivierend (Angst)",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Wille",
|
||||||
|
"Effektstärke": -0.4,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 6.17,
|
||||||
|
"Stichwort": "Schulwechsel",
|
||||||
|
"Kapitelname": "Elternhaus und Familie",
|
||||||
|
"Subkapitel": "Familiäre Ressourcen",
|
||||||
|
"Effektstärke": -0.38,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 6.15,
|
||||||
|
"Stichwort": "Körperliche Züchtigung",
|
||||||
|
"Kapitelname": "Elternhaus und Familie",
|
||||||
|
"Subkapitel": "Familiäre Ressourcen",
|
||||||
|
"Effektstärke": -0.33,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.32,
|
||||||
|
"Stichwort": "negativ-aktivierend (Depressionen)",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Wille",
|
||||||
|
"Effektstärke": -0.3,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.49,
|
||||||
|
"Stichwort": "Dachloser Dialekt",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Thrill: Motivation",
|
||||||
|
"Effektstärke": -0.29,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 8.12,
|
||||||
|
"Stichwort": "(Cyber-)Bulling",
|
||||||
|
"Kapitelname": "Klassenzimmer",
|
||||||
|
"Subkapitel": "Einflüsse im Klassenzimmer",
|
||||||
|
"Effektstärke": -0.28,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 6.07,
|
||||||
|
"Stichwort": "Geschieden",
|
||||||
|
"Kapitelname": "Elternhaus und Familie",
|
||||||
|
"Subkapitel": "Familiäre Ressourcen",
|
||||||
|
"Effektstärke": -0.26,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 8.24,
|
||||||
|
"Stichwort": "Unbeliebtheit in der Klasse",
|
||||||
|
"Kapitelname": "Klassenzimmer",
|
||||||
|
"Subkapitel": "Klassenklima",
|
||||||
|
"Effektstärke": -0.26,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"item_projection": {
|
||||||
|
"n_nodes": 169,
|
||||||
|
"n_edges": 7238,
|
||||||
|
"n_communities": 2
|
||||||
|
},
|
||||||
"meta": {
|
"meta": {
|
||||||
"theme": "dark",
|
"theme": "dark",
|
||||||
"min_abs_d": 0.0,
|
"min_abs_d": 0.0,
|
||||||
|
|||||||
246
export/network_top_extremes.json
Normal file
246
export/network_top_extremes.json
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
{
|
||||||
|
"top_positive": [
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 9.08,
|
||||||
|
"Stichwort": "Kollektive Wirksamkeitserwartung",
|
||||||
|
"Kapitelname": "Lehrperson",
|
||||||
|
"Subkapitel": "Einflüsse der Lehrperson",
|
||||||
|
"Effektstärke": 1.34,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 9.05,
|
||||||
|
"Stichwort": "Einschätzung des Leistungsniveaus durch die Lehrperson",
|
||||||
|
"Kapitelname": "Lehrperson",
|
||||||
|
"Subkapitel": "Einflüsse der Lehrperson",
|
||||||
|
"Effektstärke": 1.3,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.05,
|
||||||
|
"Stichwort": "Erkenntnisstufen",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Fähigkeiten",
|
||||||
|
"Effektstärke": 1.28,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 9.06,
|
||||||
|
"Stichwort": "Glaubwürdigkeit",
|
||||||
|
"Kapitelname": "Lehrperson",
|
||||||
|
"Subkapitel": "Einflüsse der Lehrperson",
|
||||||
|
"Effektstärke": 1.09,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 9.13,
|
||||||
|
"Stichwort": "Micro-Teaching",
|
||||||
|
"Kapitelname": "Lehrperson",
|
||||||
|
"Subkapitel": "Entwicklung von Lehrerprofessionalität",
|
||||||
|
"Effektstärke": 1.01,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 10.3,
|
||||||
|
"Stichwort": "Ergebnisorientierte Bildung",
|
||||||
|
"Kapitelname": "Curriculum",
|
||||||
|
"Subkapitel": "Andere Lehrplanbereiche",
|
||||||
|
"Effektstärke": 0.97,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.01,
|
||||||
|
"Stichwort": "Vorausgehende Fähigkeiten & Intelligenz",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Fähigkeiten",
|
||||||
|
"Effektstärke": 0.96,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.11,
|
||||||
|
"Stichwort": "Beurteilung der eigenen Leistungsfähigkeit",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Fähigkeiten",
|
||||||
|
"Effektstärke": 0.96,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.1,
|
||||||
|
"Stichwort": "Feldunabhängigkeit",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Fähigkeiten",
|
||||||
|
"Effektstärke": 0.94,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 9.07,
|
||||||
|
"Stichwort": "Klarheit der Lehrperson",
|
||||||
|
"Kapitelname": "Lehrperson",
|
||||||
|
"Subkapitel": "Einflüsse der Lehrperson",
|
||||||
|
"Effektstärke": 0.85,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.13,
|
||||||
|
"Stichwort": "Kritisches Denken",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Fähigkeiten",
|
||||||
|
"Effektstärke": 0.84,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 8.13,
|
||||||
|
"Stichwort": "Reduktion von Unterrichtsstörungen",
|
||||||
|
"Kapitelname": "Klassenzimmer",
|
||||||
|
"Subkapitel": "Einflüsse im Klassenzimmer",
|
||||||
|
"Effektstärke": 0.82,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 10.02,
|
||||||
|
"Stichwort": "Leseförderung für besondere Gruppen",
|
||||||
|
"Kapitelname": "Curriculum",
|
||||||
|
"Subkapitel": "Curriculare Programme (Lesen)",
|
||||||
|
"Effektstärke": 0.82,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 10.11,
|
||||||
|
"Stichwort": "Wiederholtes Lesen",
|
||||||
|
"Kapitelname": "Curriculum",
|
||||||
|
"Subkapitel": "Curriculare Programme (Lesen)",
|
||||||
|
"Effektstärke": 0.8,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 10.07,
|
||||||
|
"Stichwort": "Phonologische Bewusstheit",
|
||||||
|
"Kapitelname": "Curriculum",
|
||||||
|
"Subkapitel": "Curriculare Programme (Lesen)",
|
||||||
|
"Effektstärke": 0.75,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"top_negative": [
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.33,
|
||||||
|
"Stichwort": "negativ-aktivierend (Wut)",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Wille",
|
||||||
|
"Effektstärke": -0.65,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.43,
|
||||||
|
"Stichwort": "Misshandlung",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Thrill: Motivation",
|
||||||
|
"Effektstärke": -0.63,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.39,
|
||||||
|
"Stichwort": "Frühgeburt / Geburtsgewicht",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Thrill: Motivation",
|
||||||
|
"Effektstärke": -0.59,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.41,
|
||||||
|
"Stichwort": "Krankheit",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Thrill: Motivation",
|
||||||
|
"Effektstärke": -0.51,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.36,
|
||||||
|
"Stichwort": "negativ-aktivierend (Langeweile)",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Wille",
|
||||||
|
"Effektstärke": -0.46,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.42,
|
||||||
|
"Stichwort": "Körperliche Syndrome",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Thrill: Motivation",
|
||||||
|
"Effektstärke": -0.42,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.38,
|
||||||
|
"Stichwort": "kognitive Dispositionen (Prokrastination)",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Wille",
|
||||||
|
"Effektstärke": -0.41,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.31,
|
||||||
|
"Stichwort": "negativ-aktivierend (Angst)",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Wille",
|
||||||
|
"Effektstärke": -0.4,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 6.17,
|
||||||
|
"Stichwort": "Schulwechsel",
|
||||||
|
"Kapitelname": "Elternhaus und Familie",
|
||||||
|
"Subkapitel": "Familiäre Ressourcen",
|
||||||
|
"Effektstärke": -0.38,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 6.15,
|
||||||
|
"Stichwort": "Körperliche Züchtigung",
|
||||||
|
"Kapitelname": "Elternhaus und Familie",
|
||||||
|
"Subkapitel": "Familiäre Ressourcen",
|
||||||
|
"Effektstärke": -0.33,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.32,
|
||||||
|
"Stichwort": "negativ-aktivierend (Depressionen)",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Wille",
|
||||||
|
"Effektstärke": -0.3,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 5.49,
|
||||||
|
"Stichwort": "Dachloser Dialekt",
|
||||||
|
"Kapitelname": "Lernende",
|
||||||
|
"Subkapitel": "Thrill: Motivation",
|
||||||
|
"Effektstärke": -0.29,
|
||||||
|
"Systemebene": "psychisch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 8.12,
|
||||||
|
"Stichwort": "(Cyber-)Bulling",
|
||||||
|
"Kapitelname": "Klassenzimmer",
|
||||||
|
"Subkapitel": "Einflüsse im Klassenzimmer",
|
||||||
|
"Effektstärke": -0.28,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 6.07,
|
||||||
|
"Stichwort": "Geschieden",
|
||||||
|
"Kapitelname": "Elternhaus und Familie",
|
||||||
|
"Subkapitel": "Familiäre Ressourcen",
|
||||||
|
"Effektstärke": -0.26,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Thermometer_ID": 8.24,
|
||||||
|
"Stichwort": "Unbeliebtheit in der Klasse",
|
||||||
|
"Kapitelname": "Klassenzimmer",
|
||||||
|
"Subkapitel": "Klassenklima",
|
||||||
|
"Effektstärke": -0.26,
|
||||||
|
"Systemebene": "sozial"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -38,6 +38,11 @@ from config_visible_learning import (
|
|||||||
export_fig_visual,
|
export_fig_visual,
|
||||||
export_fig_png,
|
export_fig_png,
|
||||||
theme,
|
theme,
|
||||||
|
z_mode,
|
||||||
|
z_axis_labels,
|
||||||
|
show_item_projection,
|
||||||
|
show_community_labels,
|
||||||
|
top_n_extremes,
|
||||||
)
|
)
|
||||||
|
|
||||||
# -----------------------------------------
|
# -----------------------------------------
|
||||||
@ -55,6 +60,30 @@ except Exception:
|
|||||||
_styles = {}
|
_styles = {}
|
||||||
_colors = {}
|
_colors = {}
|
||||||
|
|
||||||
|
# -----------------------------------------
|
||||||
|
# Config-Fallbacks (falls Keys fehlen)
|
||||||
|
# -----------------------------------------
|
||||||
|
try:
|
||||||
|
_Z_MODE = z_mode
|
||||||
|
except Exception:
|
||||||
|
_Z_MODE = "effekt"
|
||||||
|
try:
|
||||||
|
_Z_AXIS_LABELS = z_axis_labels
|
||||||
|
except Exception:
|
||||||
|
_Z_AXIS_LABELS = {"effekt": "Effektstärke (Cohen d)", "kapitel": "Kapitel (numerischer Index)", "system": "Systemebene (0 = Psychisch, 1 = Sozial)"}
|
||||||
|
try:
|
||||||
|
_SHOW_ITEM_PROJECTION = show_item_projection
|
||||||
|
except Exception:
|
||||||
|
_SHOW_ITEM_PROJECTION = True
|
||||||
|
try:
|
||||||
|
_SHOW_COMMUNITY_LABELS = show_community_labels
|
||||||
|
except Exception:
|
||||||
|
_SHOW_COMMUNITY_LABELS = True
|
||||||
|
try:
|
||||||
|
_TOP_N_EXTREMES = int(top_n_extremes)
|
||||||
|
except Exception:
|
||||||
|
_TOP_N_EXTREMES = 15
|
||||||
|
|
||||||
# -----------------------------------------
|
# -----------------------------------------
|
||||||
# Export-Helfer
|
# Export-Helfer
|
||||||
# -----------------------------------------
|
# -----------------------------------------
|
||||||
@ -106,6 +135,29 @@ def load_data(path: str) -> pd.DataFrame:
|
|||||||
df["Kapitel"] = None
|
df["Kapitel"] = None
|
||||||
return df
|
return df
|
||||||
|
|
||||||
|
# -----------------------------------------
|
||||||
|
# Top-Listen (positiv/negativ)
|
||||||
|
# -----------------------------------------
|
||||||
|
|
||||||
|
def top_extremes(df: pd.DataFrame, n: int = 15) -> dict:
|
||||||
|
data = df.copy()
|
||||||
|
data = data[data["Systemebene"].astype(str).str.lower().isin(["psychisch", "sozial"])]
|
||||||
|
data = data.dropna(subset=["Effektstärke"]) # Sicherheit
|
||||||
|
pos = data.sort_values("Effektstärke", ascending=False).head(n)
|
||||||
|
neg = data.sort_values("Effektstärke", ascending=True).head(n)
|
||||||
|
# Konsole
|
||||||
|
print(f"\nTop +{n} (positiv):")
|
||||||
|
for _, r in pos.iterrows():
|
||||||
|
print(f" {r['Thermometer_ID']}: {r['Stichwort']} | d={float(r['Effektstärke']):.2f}")
|
||||||
|
print(f"\nTop -{n} (negativ):")
|
||||||
|
for _, r in neg.iterrows():
|
||||||
|
print(f" {r['Thermometer_ID']}: {r['Stichwort']} | d={float(r['Effektstärke']):.2f}")
|
||||||
|
return {
|
||||||
|
"top_positive": pos[["Thermometer_ID","Stichwort","Kapitelname","Subkapitel","Effektstärke","Systemebene"]].to_dict(orient="records"),
|
||||||
|
"top_negative": neg[["Thermometer_ID","Stichwort","Kapitelname","Subkapitel","Effektstärke","Systemebene"]].to_dict(orient="records"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# -----------------------------------------
|
# -----------------------------------------
|
||||||
# Netzwerk bauen
|
# Netzwerk bauen
|
||||||
# -----------------------------------------
|
# -----------------------------------------
|
||||||
@ -161,6 +213,103 @@ def build_bipartite_graph(
|
|||||||
)
|
)
|
||||||
return G
|
return G
|
||||||
|
|
||||||
|
# -----------------------------------------
|
||||||
|
# Item-Projektion (bipartit -> Item-Item) + Communities
|
||||||
|
# -----------------------------------------
|
||||||
|
from networkx.algorithms import community as nx_comm
|
||||||
|
|
||||||
|
def build_item_projection(G: nx.Graph) -> tuple[nx.Graph, dict[str,int], list[set]]:
|
||||||
|
"""Projiziert das bipartite Netz auf die Item-Seite. Zwei Items werden verbunden,
|
||||||
|
wenn sie dasselbe System teilen. Kanten-Gewicht = min(|w_i|, |w_j|).
|
||||||
|
Liefert das Item-Graph, ein Mapping node->community_id und die Community-Mengen.
|
||||||
|
"""
|
||||||
|
# Item- und System-Knoten bestimmen
|
||||||
|
items = [n for n, d in G.nodes(data=True) if d.get("bipartite") == "item"]
|
||||||
|
systems = [n for n, d in G.nodes(data=True) if d.get("bipartite") == "system"]
|
||||||
|
# Zuordnung: System -> Liste (item, |weight|)
|
||||||
|
sys_to_items: dict[str, list[tuple[str,float]]] = {}
|
||||||
|
for s in systems:
|
||||||
|
sys_to_items[s] = []
|
||||||
|
for u, v, d in G.edges(data=True):
|
||||||
|
if u in systems and v in items:
|
||||||
|
sys_to_items[u].append((v, abs(float(d.get("weight",0.0)))))
|
||||||
|
elif v in systems and u in items:
|
||||||
|
sys_to_items[v].append((u, abs(float(d.get("weight",0.0)))))
|
||||||
|
# Item-Graph aufbauen
|
||||||
|
Gi = nx.Graph()
|
||||||
|
for it in items:
|
||||||
|
nd = G.nodes[it]
|
||||||
|
Gi.add_node(it, **nd)
|
||||||
|
for s, lst in sys_to_items.items():
|
||||||
|
# Alle Paare innerhalb desselben Systems verbinden
|
||||||
|
for i in range(len(lst)):
|
||||||
|
for j in range(i+1, len(lst)):
|
||||||
|
a, wa = lst[i]
|
||||||
|
b, wb = lst[j]
|
||||||
|
w = min(wa, wb)
|
||||||
|
if Gi.has_edge(a,b):
|
||||||
|
Gi[a][b]["weight"] += w
|
||||||
|
else:
|
||||||
|
Gi.add_edge(a, b, weight=w)
|
||||||
|
if Gi.number_of_edges() == 0:
|
||||||
|
return Gi, {}, []
|
||||||
|
# Communities (gewichtete Modularity, Greedy)
|
||||||
|
coms = nx_comm.greedy_modularity_communities(Gi, weight="weight")
|
||||||
|
node2com: dict[str,int] = {}
|
||||||
|
for cid, members in enumerate(coms):
|
||||||
|
for n in members:
|
||||||
|
node2com[n] = cid
|
||||||
|
return Gi, node2com, [set(c) for c in coms]
|
||||||
|
|
||||||
|
|
||||||
|
def plot_item_projection(Gi: nx.Graph, node2com: dict[str,int], title: str = "Item-Projektion (Communities)"):
|
||||||
|
if Gi.number_of_nodes() == 0:
|
||||||
|
print("Hinweis: Item-Projektion leer (zu wenig Überlappung).")
|
||||||
|
return
|
||||||
|
pos = nx.spring_layout(Gi, seed=42, weight="weight")
|
||||||
|
# Communities zu Traces gruppieren
|
||||||
|
com_to_nodes: dict[int, list[str]] = {}
|
||||||
|
for n in Gi.nodes():
|
||||||
|
cid = node2com.get(n, -1)
|
||||||
|
com_to_nodes.setdefault(cid, []).append(n)
|
||||||
|
traces = []
|
||||||
|
# Farb-/Markerstile aus CI (zyklisch)
|
||||||
|
style_keys = [
|
||||||
|
"marker_accent", "marker_brightArea", "marker_depthArea",
|
||||||
|
"marker_positiveHighlight", "marker_negativeHighlight",
|
||||||
|
"marker_primaryLine", "marker_secondaryLine"
|
||||||
|
]
|
||||||
|
keys_cycle = style_keys * 10
|
||||||
|
for idx, (cid, nodes) in enumerate(sorted(com_to_nodes.items(), key=lambda t: t[0])):
|
||||||
|
xs = [pos[n][0] for n in nodes]
|
||||||
|
ys = [pos[n][1] for n in nodes]
|
||||||
|
htxt = []
|
||||||
|
for n in nodes:
|
||||||
|
nd = Gi.nodes[n]
|
||||||
|
htxt.append(
|
||||||
|
"Thermometer: " + str(nd.get("id","")) +
|
||||||
|
"<br>Stichwort: " + str(nd.get("label","")) +
|
||||||
|
"<br>Kapitel: " + str(nd.get("kapitelname","")) +
|
||||||
|
"<br>Subkapitel: " + str(nd.get("subkapitel","")) +
|
||||||
|
"<br>d: " + f"{nd.get('d',np.nan):.2f}"
|
||||||
|
)
|
||||||
|
mk = _styles.get(keys_cycle[idx], dict(size=8))
|
||||||
|
traces.append(go.Scatter(
|
||||||
|
x=xs, y=ys, mode="markers+text" if _SHOW_COMMUNITY_LABELS else "markers",
|
||||||
|
marker={**mk, "size": 9},
|
||||||
|
text=[str(node2com.get(n, -1)) if _SHOW_COMMUNITY_LABELS else None for n in nodes],
|
||||||
|
textposition="top center",
|
||||||
|
hovertext=htxt,
|
||||||
|
hovertemplate="%{hovertext}<extra></extra>",
|
||||||
|
name=f"Community {cid}"
|
||||||
|
))
|
||||||
|
fig = go.Figure(data=traces)
|
||||||
|
fig.update_layout(_ci_layout(title))
|
||||||
|
fig.update_xaxes(title_text="Semantische Position X (Projektion)", showticklabels=False, showgrid=False, zeroline=False)
|
||||||
|
fig.update_yaxes(title_text="Semantische Position Y (Projektion)", showticklabels=False, showgrid=False, zeroline=False)
|
||||||
|
fig.show()
|
||||||
|
export_figure(fig, "vl-network-item-projection")
|
||||||
|
|
||||||
# -----------------------------------------
|
# -----------------------------------------
|
||||||
# Layout & Visualisierung (Plotly)
|
# Layout & Visualisierung (Plotly)
|
||||||
# -----------------------------------------
|
# -----------------------------------------
|
||||||
@ -188,13 +337,13 @@ def plot_network(G: nx.Graph, title: str = "Netzwerk: Systemebenen × Thermomete
|
|||||||
x_pos, y_pos = _edge_segments(G, pos, sign="pos")
|
x_pos, y_pos = _edge_segments(G, pos, sign="pos")
|
||||||
x_neg, y_neg = _edge_segments(G, pos, sign="neg")
|
x_neg, y_neg = _edge_segments(G, pos, sign="neg")
|
||||||
|
|
||||||
line_primary = _styles.get("linie_primaryLine", dict(width=1))
|
line_positive = _styles.get("linie_positiveHighlight", dict(width=1))
|
||||||
line_secondary = _styles.get("linie_secondaryLine", dict(width=1))
|
line_negative = _styles.get("linie_negativeHighlight", dict(width=1))
|
||||||
|
|
||||||
edge_pos = go.Scatter(
|
edge_pos = go.Scatter(
|
||||||
x=x_pos, y=y_pos,
|
x=x_pos, y=y_pos,
|
||||||
mode="lines",
|
mode="lines",
|
||||||
line=line_primary,
|
line=line_positive,
|
||||||
hoverinfo="skip",
|
hoverinfo="skip",
|
||||||
showlegend=True,
|
showlegend=True,
|
||||||
name="Kanten (d ≥ 0)"
|
name="Kanten (d ≥ 0)"
|
||||||
@ -202,14 +351,14 @@ def plot_network(G: nx.Graph, title: str = "Netzwerk: Systemebenen × Thermomete
|
|||||||
edge_neg = go.Scatter(
|
edge_neg = go.Scatter(
|
||||||
x=x_neg, y=y_neg,
|
x=x_neg, y=y_neg,
|
||||||
mode="lines",
|
mode="lines",
|
||||||
line=line_secondary,
|
line=line_negative,
|
||||||
hoverinfo="skip",
|
hoverinfo="skip",
|
||||||
showlegend=True,
|
showlegend=True,
|
||||||
name="Kanten (d < 0)"
|
name="Kanten (d < 0)"
|
||||||
)
|
)
|
||||||
|
|
||||||
# System-Knoten: Marker aus CI (z. B. accent)
|
# System-Knoten: Marker aus CI (z. B. accent)
|
||||||
sys_marker = _styles.get("marker_accent", dict(size=18))
|
sys_marker = _styles.get("marker_primaryLine", dict(size=18))
|
||||||
sys_x = [pos[n][0] for n in system_nodes]
|
sys_x = [pos[n][0] for n in system_nodes]
|
||||||
sys_y = [pos[n][1] for n in system_nodes]
|
sys_y = [pos[n][1] for n in system_nodes]
|
||||||
sys_text = [G.nodes[n].get("label", n) for n in system_nodes]
|
sys_text = [G.nodes[n].get("label", n) for n in system_nodes]
|
||||||
@ -225,7 +374,7 @@ def plot_network(G: nx.Graph, title: str = "Netzwerk: Systemebenen × Thermomete
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Item-Knoten: Marker aus CI (z. B. brightArea); Größe ~ |degree_weight|
|
# Item-Knoten: Marker aus CI (z. B. brightArea); Größe ~ |degree_weight|
|
||||||
item_marker = _styles.get("marker_brightArea", dict(size=10))
|
item_marker = _styles.get("marker_secondaryLine", dict(size=10))
|
||||||
it_x = [pos[n][0] for n in item_nodes]
|
it_x = [pos[n][0] for n in item_nodes]
|
||||||
it_y = [pos[n][1] for n in item_nodes]
|
it_y = [pos[n][1] for n in item_nodes]
|
||||||
|
|
||||||
@ -266,13 +415,195 @@ def plot_network(G: nx.Graph, title: str = "Netzwerk: Systemebenen × Thermomete
|
|||||||
)
|
)
|
||||||
|
|
||||||
fig = go.Figure(data=[edge_pos, edge_neg, systems_trace, items_trace])
|
fig = go.Figure(data=[edge_pos, edge_neg, systems_trace, items_trace])
|
||||||
|
# CI-Layout und inhaltliche Achsentitel (2D: Semantische Position aus Layout)
|
||||||
fig.update_layout(_ci_layout(title))
|
fig.update_layout(_ci_layout(title))
|
||||||
# Achsen & Grid neutral halten, keine Beschriftungen im Plot (alles im Hover)
|
fig.update_xaxes(
|
||||||
fig.update_xaxes(showticklabels=False, showgrid=False, zeroline=False)
|
title_text="Semantische Position X (Layout)",
|
||||||
fig.update_yaxes(showticklabels=False, showgrid=False, zeroline=False)
|
showticklabels=False, showgrid=False, zeroline=False
|
||||||
|
)
|
||||||
|
fig.update_yaxes(
|
||||||
|
title_text="Semantische Position Y (Layout)",
|
||||||
|
showticklabels=False, showgrid=False, zeroline=False
|
||||||
|
)
|
||||||
fig.show()
|
fig.show()
|
||||||
export_figure(fig, "vl-network")
|
export_figure(fig, "vl-network")
|
||||||
|
|
||||||
|
def _edge_segments_3d(G: nx.Graph, pos_xy: dict[str, tuple[float, float]], z_map: dict[str, float], sign: str | None = None):
|
||||||
|
"""Erzeugt x,y,z-Koordinaten-Listen für 3D-Liniensegmente (mit None-Trennern). Optional nach Vorzeichen filtern."""
|
||||||
|
xs, ys, zs = [], [], []
|
||||||
|
for u, v, d in G.edges(data=True):
|
||||||
|
if sign and d.get("sign") != sign:
|
||||||
|
continue
|
||||||
|
x0, y0 = pos_xy[u]
|
||||||
|
x1, y1 = pos_xy[v]
|
||||||
|
z0 = float(z_map.get(u, 0.0))
|
||||||
|
z1 = float(z_map.get(v, 0.0))
|
||||||
|
xs += [x0, x1, None]
|
||||||
|
ys += [y0, y1, None]
|
||||||
|
zs += [z0, z1, None]
|
||||||
|
return xs, ys, zs
|
||||||
|
|
||||||
|
|
||||||
|
def plot_network_3d(G: nx.Graph, z_mode: str = "effekt", title: str = "3D: Systemebenen × Thermometer", seed: int = 42):
|
||||||
|
"""
|
||||||
|
Semantische 3D-Ansicht:
|
||||||
|
- z_mode = "effekt": z = Effektstärke (Items), Systeme z=0
|
||||||
|
- z_mode = "kapitel": z = Kapitelnummer (Items), Systeme unterhalb der Items (min_z - 0.5)
|
||||||
|
- z_mode = "system": z = 0 (psychisch), 1 (sozial), Items = Mittelwert ihrer Systemnachbarn
|
||||||
|
x/y stammen aus einem 2D-Spring-Layout (stabile, gut lesbare Projektion), z ist semantisch belegt.
|
||||||
|
"""
|
||||||
|
styles = _styles
|
||||||
|
colors = _colors
|
||||||
|
|
||||||
|
# 2D-Layout für X/Y (stabile Projektion)
|
||||||
|
pos_xy = nx.spring_layout(G, seed=seed, k=None, weight="weight", dim=2)
|
||||||
|
|
||||||
|
# Z-Koordinaten je Knoten ermitteln
|
||||||
|
z_map: dict[str, float] = {}
|
||||||
|
if z_mode == "effekt":
|
||||||
|
for n, d in G.nodes(data=True):
|
||||||
|
if d.get("bipartite") == "item":
|
||||||
|
z_map[n] = float(d.get("d", 0.0))
|
||||||
|
else:
|
||||||
|
z_map[n] = 0.0
|
||||||
|
elif z_mode == "kapitel":
|
||||||
|
item_z_vals = []
|
||||||
|
for n, d in G.nodes(data=True):
|
||||||
|
if d.get("bipartite") == "item":
|
||||||
|
try:
|
||||||
|
# Kapitelnummer aus Kapitelname kann alphanumerisch sein; wir nutzen, wenn vorhanden, numerische "Kapitel"
|
||||||
|
# Falls keine numerische Kapitelspalte existiert, wird 0 gesetzt.
|
||||||
|
kap = d.get("kapitelname", "")
|
||||||
|
# Fallback: im Nodes-Attribut existiert keine numerische Kapitelnummer; daher 0
|
||||||
|
z_map[n] = float(d.get("kapitel", 0.0)) if "kapitel" in d else 0.0
|
||||||
|
except Exception:
|
||||||
|
z_map[n] = 0.0
|
||||||
|
item_z_vals.append(z_map[n])
|
||||||
|
min_z = min(item_z_vals) if item_z_vals else 0.0
|
||||||
|
for n, d in G.nodes(data=True):
|
||||||
|
if d.get("bipartite") == "system":
|
||||||
|
z_map[n] = float(min_z) - 0.5
|
||||||
|
elif z_mode == "system":
|
||||||
|
# Systeme klar trennen
|
||||||
|
for n, d in G.nodes(data=True):
|
||||||
|
if d.get("bipartite") == "system":
|
||||||
|
lbl = str(d.get("label", "")).strip().lower()
|
||||||
|
z_map[n] = 0.0 if "psych" in lbl else 1.0
|
||||||
|
# Items: Mittelwert der z-Werte ihrer System-Nachbarn (im bipartiten Graphen genau einer)
|
||||||
|
for n, d in G.nodes(data=True):
|
||||||
|
if d.get("bipartite") == "item":
|
||||||
|
zs = []
|
||||||
|
for nbr in G[n]:
|
||||||
|
zs.append(z_map.get(nbr, 0.0))
|
||||||
|
z_map[n] = float(np.mean(zs)) if zs else 0.0
|
||||||
|
else:
|
||||||
|
# Unbekannter Modus -> alle 0
|
||||||
|
z_map = {n: 0.0 for n in G.nodes()}
|
||||||
|
|
||||||
|
# Knotenlisten
|
||||||
|
system_nodes = [n for n, d in G.nodes(data=True) if d.get("bipartite") == "system"]
|
||||||
|
item_nodes = [n for n, d in G.nodes(data=True) if d.get("bipartite") == "item"]
|
||||||
|
|
||||||
|
# Kanten (pos/neg) vorbereiten
|
||||||
|
x_pos, y_pos, z_pos = _edge_segments_3d(G, pos_xy, z_map, sign="pos")
|
||||||
|
x_neg, y_neg, z_neg = _edge_segments_3d(G, pos_xy, z_map, sign="neg")
|
||||||
|
|
||||||
|
line_positive = styles.get("linie_positiveHighlight", dict(width=1))
|
||||||
|
line_negative = styles.get("linie_negativeHighlight", dict(width=1))
|
||||||
|
|
||||||
|
edge_pos = go.Scatter3d(
|
||||||
|
x=x_pos, y=y_pos, z=z_pos,
|
||||||
|
mode="lines",
|
||||||
|
line=line_positive,
|
||||||
|
hoverinfo="skip",
|
||||||
|
showlegend=True,
|
||||||
|
name="Kanten (d ≥ 0)"
|
||||||
|
)
|
||||||
|
edge_neg = go.Scatter3d(
|
||||||
|
x=x_neg, y=y_neg, z=z_neg,
|
||||||
|
mode="lines",
|
||||||
|
line=line_negative,
|
||||||
|
hoverinfo="skip",
|
||||||
|
showlegend=True,
|
||||||
|
name="Kanten (d < 0)"
|
||||||
|
)
|
||||||
|
|
||||||
|
# System-Knoten
|
||||||
|
sys_marker = styles.get("marker_primaryLine", dict(size=18))
|
||||||
|
sys_x = [pos_xy[n][0] for n in system_nodes]
|
||||||
|
sys_y = [pos_xy[n][1] for n in system_nodes]
|
||||||
|
sys_z = [z_map[n] for n in system_nodes]
|
||||||
|
sys_text = [G.nodes[n].get("label", n) for n in system_nodes]
|
||||||
|
sys_hover = [f"Systemebene: {G.nodes[n].get('label','')}" for n in system_nodes]
|
||||||
|
|
||||||
|
systems_trace = go.Scatter3d(
|
||||||
|
x=sys_x, y=sys_y, z=sys_z, mode="markers",
|
||||||
|
marker={**sys_marker, "size": 10},
|
||||||
|
text=sys_text,
|
||||||
|
hovertext=sys_hover,
|
||||||
|
hovertemplate="%{hovertext}<extra></extra>",
|
||||||
|
name="System"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Item-Knoten: Thermometer im Sekundärstil (gleiches Marker-Design für +/-); Kanten behalten Vorzeichenfarben
|
||||||
|
pos_marker = styles.get("marker_secondaryLine", dict(size=6))
|
||||||
|
neg_marker = styles.get("marker_secondaryLine", dict(size=6))
|
||||||
|
|
||||||
|
pos_x, pos_y, pos_z, pos_hover = [], [], [], []
|
||||||
|
neg_x, neg_y, neg_z, neg_hover = [], [], [], []
|
||||||
|
for n in item_nodes:
|
||||||
|
x, y = pos_xy[n]
|
||||||
|
z = z_map[n]
|
||||||
|
nd = G.nodes[n]
|
||||||
|
hover = (
|
||||||
|
"Thermometer: " + str(nd.get("id","")) +
|
||||||
|
"<br>Stichwort: " + str(nd.get("label","")) +
|
||||||
|
"<br>Kapitel: " + str(nd.get("kapitelname","")) +
|
||||||
|
"<br>Subkapitel: " + str(nd.get("subkapitel","")) +
|
||||||
|
"<br>d: " + f"{nd.get('d',np.nan):.2f}"
|
||||||
|
)
|
||||||
|
if float(nd.get("d", 0.0)) >= 0:
|
||||||
|
pos_x.append(x); pos_y.append(y); pos_z.append(z); pos_hover.append(hover)
|
||||||
|
else:
|
||||||
|
neg_x.append(x); neg_y.append(y); neg_z.append(z); neg_hover.append(hover)
|
||||||
|
|
||||||
|
items_pos_trace = go.Scatter3d(
|
||||||
|
x=pos_x, y=pos_y, z=pos_z, mode="markers",
|
||||||
|
marker=pos_marker,
|
||||||
|
hovertext=pos_hover,
|
||||||
|
hovertemplate="%{hovertext}<extra></extra>",
|
||||||
|
name="Thermometer (d ≥ 0)"
|
||||||
|
)
|
||||||
|
items_neg_trace = go.Scatter3d(
|
||||||
|
x=neg_x, y=neg_y, z=neg_z, mode="markers",
|
||||||
|
marker=neg_marker,
|
||||||
|
hovertext=neg_hover,
|
||||||
|
hovertemplate="%{hovertext}<extra></extra>",
|
||||||
|
name="Thermometer (d < 0)"
|
||||||
|
)
|
||||||
|
|
||||||
|
fig = go.Figure(data=[edge_pos, edge_neg, systems_trace, items_pos_trace, items_neg_trace])
|
||||||
|
fig.update_layout(_ci_layout(f"{title} – z: {z_mode}"))
|
||||||
|
# Achsentitel mit inhaltlicher Bedeutung setzen
|
||||||
|
z_title = _Z_AXIS_LABELS.get(z_mode, "Z")
|
||||||
|
|
||||||
|
fig.update_scenes(
|
||||||
|
xaxis=dict(
|
||||||
|
title="Semantische Position X (Layout)",
|
||||||
|
showticklabels=False, showgrid=False, zeroline=False
|
||||||
|
),
|
||||||
|
yaxis=dict(
|
||||||
|
title="Semantische Position Y (Layout)",
|
||||||
|
showticklabels=False, showgrid=False, zeroline=False
|
||||||
|
),
|
||||||
|
zaxis=dict(
|
||||||
|
title=z_title,
|
||||||
|
showticklabels=False, showgrid=False, zeroline=False
|
||||||
|
),
|
||||||
|
)
|
||||||
|
fig.show()
|
||||||
|
export_figure(fig, f"vl-network-3d-{z_mode}")
|
||||||
|
|
||||||
# -----------------------------------------
|
# -----------------------------------------
|
||||||
# Einfache Metriken & Export
|
# Einfache Metriken & Export
|
||||||
# -----------------------------------------
|
# -----------------------------------------
|
||||||
@ -311,7 +642,8 @@ def run_network_analysis(
|
|||||||
min_abs_d: float = 0.00,
|
min_abs_d: float = 0.00,
|
||||||
kapitel_filter: list[int] | None = None,
|
kapitel_filter: list[int] | None = None,
|
||||||
subkapitel_filter: list[str] | None = None,
|
subkapitel_filter: list[str] | None = None,
|
||||||
seed: int = 42
|
seed: int = 42,
|
||||||
|
z_mode: str = "effekt"
|
||||||
):
|
):
|
||||||
df = load_data(csv_path)
|
df = load_data(csv_path)
|
||||||
# Datenqualität knapp loggen
|
# Datenqualität knapp loggen
|
||||||
@ -333,14 +665,34 @@ def run_network_analysis(
|
|||||||
|
|
||||||
plot_network(G, title="Netzwerk: Systemebenen × Thermometer (Kanten: Effektstärke)", seed=seed)
|
plot_network(G, title="Netzwerk: Systemebenen × Thermometer (Kanten: Effektstärke)", seed=seed)
|
||||||
|
|
||||||
|
# 3D-Ansicht mit semantischer z-Achse
|
||||||
|
plot_network_3d(G, z_mode=z_mode, title="Netzwerk (3D): semantische z-Achse", seed=seed)
|
||||||
|
|
||||||
summary = summarize_network(G)
|
summary = summarize_network(G)
|
||||||
print("\nSystemgewicht-Summen:", summary["system_weight_sums"])
|
print("\nSystemgewicht-Summen:", summary["system_weight_sums"])
|
||||||
print("\nTop-Items (weighted degree):")
|
print("\nTop-Items (weighted degree):")
|
||||||
for r in summary["top_items_by_weighted_degree"]:
|
for r in summary["top_items_by_weighted_degree"]:
|
||||||
print(f" {r['Thermometer_ID']}: {r['Stichwort']} | d={r['Effektstärke']:.2f} | wd={r['weighted_degree_abs']:.2f}")
|
print(f" {r['Thermometer_ID']}: {r['Stichwort']} | d={r['Effektstärke']:.2f} | wd={r['weighted_degree_abs']:.2f}")
|
||||||
|
|
||||||
|
# Top-Listen exportieren
|
||||||
|
extremes = top_extremes(df, n=_TOP_N_EXTREMES)
|
||||||
|
export_json(extremes, "network_top_extremes.json")
|
||||||
|
|
||||||
|
# Item-Projektion + Communities (optional)
|
||||||
|
item_proj_summary = {}
|
||||||
|
if _SHOW_ITEM_PROJECTION:
|
||||||
|
Gi, node2com, coms = build_item_projection(G)
|
||||||
|
plot_item_projection(Gi, node2com, title="Item-Projektion (Communities)")
|
||||||
|
item_proj_summary = {
|
||||||
|
"n_nodes": Gi.number_of_nodes(),
|
||||||
|
"n_edges": Gi.number_of_edges(),
|
||||||
|
"n_communities": len(coms),
|
||||||
|
}
|
||||||
|
|
||||||
# Export JSON
|
# Export JSON
|
||||||
payload = {
|
payload = {
|
||||||
|
"extremes": extremes,
|
||||||
|
"item_projection": item_proj_summary,
|
||||||
"meta": {
|
"meta": {
|
||||||
"theme": theme,
|
"theme": theme,
|
||||||
"min_abs_d": float(min_abs_d),
|
"min_abs_d": float(min_abs_d),
|
||||||
@ -384,6 +736,6 @@ if __name__ == "__main__":
|
|||||||
min_abs_d=0.00,
|
min_abs_d=0.00,
|
||||||
kapitel_filter=None,
|
kapitel_filter=None,
|
||||||
subkapitel_filter=None,
|
subkapitel_filter=None,
|
||||||
seed=42
|
seed=42,
|
||||||
|
z_mode=_Z_MODE
|
||||||
)
|
)
|
||||||
|
|
||||||
Reference in New Issue
Block a user