Штучний інтелект та VR-освіта. Епоха когнітивних цифрових двійників

Mriia Research Hub Multimodal Cognitive Digital Twins HMMI / PRE / POST

Multimodal Cognitive Digital Twins Мультимодальні когнітивні цифрові двійники

Тут зберігаються матеріали експерименту, дані, структура тестів, результати PRE/POST, обчислення Human Multimodal Misleadingness Index (HMMI), а також код R для аналітики, візуалізацій і перевірки гіпотез.

This page stores the experimental materials, data structure, PRE/POST results, Human Multimodal Misleadingness Index (HMMI) calculations, and R code used for analytics, visualizations, and hypothesis testing.

Що міститься тут / What is stored here

  • 250 видів тестів / 250 test types
  • Графічні, текстові та змішані завдання / Graphical, textual, and mixed tasks
  • PRE та POST вимірювання HMMI / PRE and POST HMMI measurements
  • R-код для статистичного аналізу / R code for statistical analysis
  • Матеріали експерименту та дослідницькі структури / Experimental materials and research structures

Базова платформа / Base platform

Базова платформа з відкритим кодом: https://gpt.iis.org.ua/

Open-source base platform: https://gpt.iis.org.ua/

Human Multimodal Misleadingness Index (HMMI)

Порівнюйте базові та підсумкові значення індексу стійкості до введення в оману у візуальних, текстових та змішаних завданнях.

Compare baseline and post-intervention values of learner resistance to misleading visual, textual, and mixed materials.

Українською

У цьому розділі акумульовано всі ключові дані експерименту Multimodal Cognitive Digital Twins: структура тестів, моделі інтерпретації, R-скрипти, підрахунок інтегрального індексу HMMI, а також результати до і після навчального впливу.

Для ознайомлення у відкритому режимі доступно лише 1% інформації. Повний доступ надається за запитом після публікації статті “Multimodal Cognitive Digital Twins: Modeling the Impact of Misleading Charts and Texts in School-Based Learning”.

In English

This section stores the key experimental resources of Multimodal Cognitive Digital Twins: test structures, interpretation models, R scripts, integral HMMI calculations, and pre/post intervention results.

Only 1% of the information is available for free preview. Full access is provided upon request after publication of the article “Multimodal Cognitive Digital Twins: Modeling the Impact of Misleading Charts and Texts in School-Based Learning”.

Перейти на платформу / Open the platform

Переглянути відкриту базову платформу: gpt.iis.org.ua

Відкрити / Open
Code R
 
R version 4.5.2 (2025-10-31) — “[Not] Part in a Rumble”
Copyright (C) 2025 The R Foundation for Statistical Computing
Platform: aarch64-apple-darwin20
 
R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type ‘license()’ or ‘licence()’ for distribution details.
 
  Natural language support but running in an English locale
 
R is a collaborative project with many contributors.
Type ‘contributors()’ for more information and
‘citation()’ on how to cite R or R packages in publications.
 
Type ‘demo()’ for some demos, ‘help()’ for on-line help, or
‘help.start()’ for an HTML browser interface to help.
Type ‘q()’ to quit R.
 
[Workspace loaded from ~/.RData]
 
> library(DiagrammeR)
> grViz(“
+ digraph school_digital_twin_vertical {
+   graph [
+     layout = dot,
+     rankdir = TB,
+     bgcolor = white,
+     nodesep = 0.35,
+     ranksep = 0.55,
+     splines = ortho
+   ]
+   node [
+     shape = box,
+     style = ’rounded,filled’,
+     fontname = Helvetica,
+     fontsize = 20,
+     color = ‘#2F5D8A’,
+     penwidth = 1.8,
+     fillcolor = ‘#F8FBFF’,
+     margin = 0.14
+   ]
+   edge [
+     color = ‘#2F5D8A’,
+     penwidth = 1.5,
+     arrowsize = 0.8
+   ]
+   env [
+     label = ‘School-based learning environment’,
+     fillcolor = ‘#EAF2F8’,
+     width = 4.4,
+     height = 0.8,
+     fontsize = 24
+   ]
+   task [
+     label = ‘Task design\\n(misleading items)’,
+     fillcolor = ‘#FFFDF7’,
+     width = 3.2,
+     fontsize = 18
+   ]
+   teach [
+     label = ‘Teacher-led instruction’,
+     fillcolor = ‘#FFFDF7’,
+     width = 3.2,
+     fontsize = 18
+   ]
+   resp [
+     label = ‘Learner responses\\n(MCQ + open / handwritten)’,
+     fillcolor = ‘#FFFDF7’,
+     width = 3.6,
+     fontsize = 18
+   ]
+   twin [
+     label = ‘Student digital twin’,
+     fillcolor = ‘#FDFEFE’,
+     width = 3.3,
+     height = 0.78,
+     fontsize = 22
+   ]
+   core [
+     label = ‘Multimodal cognitive learner model\\n\\nM = (Charts, Texts, Mixed Tasks, Confidence, Persistence, Reasoning)’,
+     fillcolor = ‘#F8F9F9’,
+     color = ‘#1B2A6B’,
+     penwidth = 2.6,
+     width = 6.4,
+     height = 1.2,
+     fontsize = 18
+   ]
+   ai [
+     label = ‘AI analysis\\n(OCR, LLM, scoring)’,
+     fillcolor = ‘#FFFDF7’,
+     width = 3.3,
+     fontsize = 18
+   ]
+   stat [
+     label = ‘Statistical metamodeling\\n(HMMI, subindices, group comparisons)’,
+     fillcolor = ‘#FDFEFE’,
+     width = 4.1,
+     height = 0.95,
+     fontsize = 18
+   ]
+   vis [
+     label = ‘Visual learner model\\n(dashboard, profiles, adaptive support)’,
+     fillcolor = ‘#FDFEFE’,
+     width = 4.1,
+     height = 0.95,
+     fontsize = 18
+   ]
+   adapt [
+     label = ‘Adaptive feedback\\nand posttest updating’,
+     fillcolor = ‘#FFFDF7’,
+     width = 3.6,
+     fontsize = 18
+   ]
+   env -> task
+   task -> teach
+   teach -> resp
+   resp -> twin
+   twin -> core
+   core -> ai
+   ai -> stat
+   stat -> vis
+   vis -> adapt
+   left_anchor  [label = ”, shape = point, width = 0.01, height = 0.01, style = invis]
+   right_anchor [label = ”, shape = point, width = 0.01, height = 0.01, style = invis]
+   {rank = same; left_anchor; adapt; right_anchor;}
+   adapt -> right_anchor [arrowhead = none]
+   right_anchor -> left_anchor [arrowhead = none]
+   left_anchor -> twin [dir = back]
+   left_anchor -> right_anchor [style = invis, weight = 20]
+ }
+ “)
> library(ggplot2)
> df <- data.frame(
+     Condition = c(“Control”, “Generic support”, “Adaptive digital twin”),
+     Pretest = c(0.55, 0.55, 0.55),
+     Posttest = c(0.51, 0.43, 0.33)
+ )
> df_long <- rbind(
+     data.frame(Condition = df$Condition, Phase = “Pretest”, HMMI = df$Pretest),
+     data.frame(Condition = df$Condition, Phase = “Posttest”, HMMI = df$Posttest)
+ )
> ggplot(df_long, aes(x = Condition, y = HMMI, fill = Phase)) +
+     geom_col(position = “dodge”, width = 0.7) +
+     labs(
+         title = “Illustrative reduction in learner vulnerability”,
+         subtitle = “Pretest-posttest comparison across instructional conditions”,
+         x = NULL,
+         y = “Mean HMMI”
+     ) +
+     theme_minimal(base_size = 13) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         axis.text.x = element_text(angle = 10, hjust = 1)
+     )
> hmmi_post ~ hmmi_pre + condition + data_literacy + grade_group +
+     (1 | learner_id)
hmmi_post ~ hmmi_pre + condition + data_literacy + grade_group + 
    (1 | learner_id)
> hmmi_post ~ hmmi_pre + condition + data_literacy + grade_group +
+     (1 | learner_id)
hmmi_post ~ hmmi_pre + condition + data_literacy + grade_group + 
    (1 | learner_id)
> # =========================================
> # 0. Packages
> # =========================================
> library(lme4)
Loading required package: Matrix
> library(emmeans)
Error in library(emmeans) : there is no package called ‘emmeans’
 
> install.packages(“emmeans”)
also installing the dependency ‘estimability’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/estimability_1.5.1.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/emmeans_2.0.2.tgz’
 
The downloaded binary packages are in
/var/folders/n6/295fw91d3jz7qtpgw5zm41_r0000gn/T//RtmpxADw6P/downloaded_packages
> library(emmeans)
Welcome to emmeans.
Caution: You lose important information if you filter this package’s results.
See ‘? untidy’
> install.packages(c(“lme4”, “emmeans”, “ggplot2”, “dplyr”, “tidyr”))
also installing the dependency ‘reformulas’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/reformulas_0.4.4.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/lme4_2.0-1.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/emmeans_2.0.2.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/ggplot2_4.0.2.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/dplyr_1.2.0.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/tidyr_1.3.2.tgz’
 
The downloaded binary packages are in
/var/folders/n6/295fw91d3jz7qtpgw5zm41_r0000gn/T//RtmpxADw6P/downloaded_packages
> library(lme4)
> library(emmeans)
> library(ggplot2)
> library(dplyr)
 
Attaching package: ‘dplyr’
 
The following objects are masked from ‘package:stats’:
 
    filter, lag
 
The following objects are masked from ‘package:base’:
 
    intersect, setdiff, setequal, union
> library(tidyr)
 
Attaching package: ‘tidyr’
 
The following objects are masked from ‘package:Matrix’:
 
    expand, pack, unpack
> install.packages(c(“lme4”, “emmeans”, “ggplot2”, “dplyr”, “tidyr”))
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/lme4_2.0-1.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/emmeans_2.0.2.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/ggplot2_4.0.2.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/dplyr_1.2.0.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/tidyr_1.3.2.tgz’
 
The downloaded binary packages are in
/var/folders/n6/295fw91d3jz7qtpgw5zm41_r0000gn/T//RtmpxADw6P/downloaded_packages
> install.packages(c(“lme4”, “emmeans”, “ggplot2”, “dplyr”, “tidyr”))
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/lme4_2.0-1.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/emmeans_2.0.2.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/ggplot2_4.0.2.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/dplyr_1.2.0.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/tidyr_1.3.2.tgz’
 
The downloaded binary packages are in
/var/folders/n6/295fw91d3jz7qtpgw5zm41_r0000gn/T//RtmpxADw6P/downloaded_packages
> # =========================================
> # 0. Packages
> # =========================================
> library(lme4)
> library(emmeans)
> library(ggplot2)
> library(dplyr)
> # —————————————–
> # Expected data structure
> # —————————————–
> # df should contain at least:
> # learner_id, item_id, accuracy, version,
> # misleading_type, data_literacy, condition,
> # grade_group, confidence, persistence,
> # deviation, hmmi, hmmi_pre, hmmi_post
> #
> # version: “non_misleading”, “misleading”
> # condition: “control”, “generic”, “adaptive”
> # grade_group: “5_8”, “9_11”
> # Make sure variables are coded as factors
> df <- df %>%
+     mutate(
+         learner_id = factor(learner_id),
+         item_id = factor(item_id),
+         version = factor(version, levels = c(“non_misleading”, “misleading”)),
+         misleading_type = factor(misleading_type),
+         condition = factor(condition, levels = c(“control”, “generic”, “adaptive”)),
+         grade_group = factor(grade_group, levels = c(“5_8”, “9_11”))
+     )
Error in `mutate()`:
ℹ In argument: `learner_id = factor(learner_id)`.
Caused by error:
! object ‘learner_id’ not found
Run `rlang::last_trace()` to see where the error occurred.
 
> # Завантаження необхідних бібліотек
> library(tidyverse)
── Attaching core tidyverse packages ─────────────────────────────────── tidyverse 2.0.0 ──
✔ forcats   1.0.1     ✔ readr     2.2.0
✔ lubridate 1.9.4     ✔ stringr   1.6.0
✔ purrr     1.2.0     ✔ tibble    3.3.0
── Conflicts ───────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ tidyr::expand() masks Matrix::expand()
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
✖ tidyr::pack()   masks Matrix::pack()
✖ tidyr::unpack() masks Matrix::unpack()
ℹ Use the conflicted package to force all conflicts to become errors
> library(ggcorrplot)
> library(gridExtra)
 
Attaching package: ‘gridExtra’
 
The following object is masked from ‘package:dplyr’:
 
    combine
> # Читання даних (використовуємо ваш роздільник 😉
> df <- read.csv(“journal_statistical_template_280_students.csv”, sep = “;”)
Error in file(file, “rt”) : cannot open the connection
In addition: Warning message:
In file(file, “rt”) :
  cannot open file ‘journal_statistical_template_280_students.csv’: No such file or directory
 
> він тут /Users/vasylzalizko/Downloads/journal_statistical_template_280_students.csv
Error: unexpected symbol in “він тут”
 
> /Users/vasylzalizko/Downloads/journal_statistical_template_280_students.csv
Error: unexpected ‘/’ in “/”
 
> # Вказуємо повний шлях до файлу
> file_path <- “/Users/vasylzalizko/Downloads/journal_statistical_template_280_students.csv”
> # Читаємо дані з правильним роздільником
> df <- read.csv(file_path, sep = “;”)
> # Перевірка: виведемо перші 5 рядків, щоб переконатися, що все завантажилось
> head(df)
  learner_id grade_group condition age gender V_index_pre T_index_pre M_index_pre3
1       S001         5-8   control  10      F        0,67        0,65         0,62
2       S002         5-8   control  10      F         0,5         0,5          0,5
3       S003         5-8   control  10      F         0,6         0,4          0,3
4       S004         5-8   control  10      M         0,8         0,8          0,6
5       S005         5-8   control  10      M       0,553       0,341        0,488
6       S006         5-8   control  10      M       0,662       0,591        0,481
  HMMI_index_pre
1    0,646338386
2            0,5
3    0,416016765
4    0,726848237
5    0,451474381
6    0,573055716
> library(ggplot2)
> # 1. Візуалізація: Як маніпулятивні графіки (Misleading) впливають на фінальний тест
> # (Замініть ‘Misleading_Chart_Flag’ та ‘Post_Test_Score’ на точні назви колонок з вашого файлу)
> ggplot(df, aes(x = as.factor(Misleading_Chart_Flag), y = Post_Test_Score, fill = as.factor(Misleading_Chart_Flag))) +
+     geom_boxplot(alpha = 0.7) +
+     scale_fill_manual(values = c(“#4CAF50”, “#FF5722”), labels = c(“Correct”, “Misleading”)) +
+     labs(title = “Cognitive Impact of Misleading Charts”,
+          subtitle = “Analysis for Digital Twin Modeling”,
+          x = “Information Mode”, 
+          y = “Learning Outcome Score”,
+          fill = “Condition”) +
+     theme_minimal()
Error in `geom_boxplot()`:
! Problem while computing aesthetics.
ℹ Error occurred in the 1st layer.
Caused by error:
! object ‘Misleading_Chart_Flag’ not found
Run `rlang::last_trace()` to see where the error occurred.
 
> # 1. Завантаження бібліотек
> if (!require(“ggplot2”)) install.packages(“ggplot2”)
> if (!require(“ggcorrplot”)) install.packages(“ggcorrplot”)
> if (!require(“dplyr”)) install.packages(“dplyr”)
> library(ggplot2)
> library(ggcorrplot)
> library(dplyr)
> # 2. Правильне читання файлу (враховуємо ; та кому , як роздільник десяткових)
> # Вкажіть ваш повний шлях до файлу
> file_path <- “journal_statistical_template_280_students.csv”
> df <- read.csv(file_path, sep = “;”, dec = “,”)
Error in file(file, “rt”) : cannot open the connection
In addition: Warning message:
In file(file, “rt”) :
  cannot open file ‘journal_statistical_template_280_students.csv’: No such file or directory
 
> # 1. ЗАВАНТАЖЕННЯ ТА ПІДГОТОВКА ДАНИХ
> # Виберіть файл у вікні, що відкриється
> df <- read.csv(file.choose(), sep = “;”, dec = “,”)
> # Перевірка (має вивести назви колонок: learner_id, condition, V_index_pre…)
> colnames(df)
[1] “learner_id”     “grade_group”    “condition”      “age”            “gender”        
[6] “V_index_pre”    “T_index_pre”    “M_index_pre3”   “HMMI_index_pre”
> # 2. ВІЗУАЛІЗАЦІЯ 1: Кореляційна матриця (Когнітивні зв’язки)
> # Показує, як візуальне сприйняття (V) корелює з текстовим (T)
> if (!require(“ggcorrplot”)) install.packages(“ggcorrplot”)
> library(ggcorrplot)
> numeric_cols <- df[, c(“V_index_pre”, “T_index_pre”, “M_index_pre3”, “HMMI_index_pre”)]
> corr <- cor(numeric_cols, use = “complete.obs”)
> ggcorrplot(corr, hc.order = TRUE, type = “lower”, lab = TRUE, 
+            title = “Cognitive Indices Correlation Matrix”,
+            colors = c(“#E4672E”, “white”, “#6D9EC1”))
Warning message:
`aes_string()` was deprecated in ggplot2 3.0.0.
ℹ Please use tidy evaluation idioms with `aes()`.
ℹ See also `vignette(“ggplot2-in-packages”)` for more information.
ℹ The deprecated feature was likely used in the ggcorrplot package.
  Please report the issue at <https://github.com/kassambara/ggcorrplot/issues>.
This warning is displayed once per session.
Call lifecycle::last_lifecycle_warnings() to see where this warning was generated. 
> # 3. ВІЗУАЛІЗАЦІЯ 2: Розподіл HMMI за умовами (Condition)
> # Аналіз того, як різні режими (control/generic/adaptive) впливають на гібридний індекс
> library(ggplot2)
> ggplot(df, aes(x = condition, y = HMMI_index_pre, fill = condition)) +
+     geom_boxplot(alpha = 0.7) +
+     geom_jitter(width = 0.15, alpha = 0.2) +
+     theme_minimal() +
+     labs(title = “HMMI Score Distribution by Learning Condition”,
+          x = “Instructional Design Mode”,
+          y = “Hybrid Multimodal Index (HMMI)”)
> # 4. ВІЗУАЛІЗАЦІЯ 3: “Диссонанс” між Візуалом та Текстом
> # Допомагає знайти учнів, які “ведуться” на помилкові графіки
> ggplot(df, aes(x = T_index_pre, y = V_index_pre, color = condition)) +
+     geom_point(alpha = 0.6) +
+     geom_smooth(method = “lm”, se = FALSE) +
+     theme_light() +
+     labs(title = “Visual-Textual Cognitive Mapping”,
+          x = “Text Index (T)”,
+          y = “Visual Index (V)”)
`geom_smooth()` using formula = ‘y ~ x’
> # =========================================
> # 1. LOAD AND CLEAN DATA
> # =========================================
> library(dplyr)
> df <- read.csv(“/Users/vasylzalizko/Book2026.csv”,
+                sep = “;”,
+                stringsAsFactors = FALSE,
+                check.names = TRUE)
> # Перетворення десяткових ком на крапки
> to_num <- function(x) as.numeric(gsub(“,”, “.”, x, fixed = TRUE))
> num_cols <- c(“age”, “V_index_pre”, “T_index_pre”, “M_index_pre3”,
+               “HMMI_index_pre”, “HMMI_index_pre.1”)
> for (col in intersect(num_cols, names(df))) {
+     df[[col]] <- to_num(df[[col]])
+ }
> # Очищення категорій
> df$condition <- tolower(trimws(df$condition))
> df$grade_group <- trimws(df$grade_group)
> df$gender <- trimws(df$gender)
> # За потреби перейменувати дубльований стовпчик
> # Якщо ти знаєш, що HMMI_index_pre.1 = наприклад confidence_global або auxiliary score,
> # перейменуй його осмислено.
> names(df)[names(df) == “HMMI_index_pre.1”] <- “aux_index”
> # Перевірка
> str(df)
‘data.frame’: 280 obs. of  10 variables:
 $ learner_id    : chr  “S001” “S002” “S003” “S004” …
 $ grade_group   : chr  “5-8” “5-8” “5-8” “5-8” …
 $ condition     : chr  “control” “control” “control” “control” …
 $ age           : num  10 10 10 10 10 10 10 10 10 10 …
 $ gender        : chr  “F” “F” “F” “M” …
 $ V_index_pre   : num  0.67 0.5 0.6 0.8 0.553 0.662 0.511 0.544 0.341 0.561 …
 $ T_index_pre   : num  0.65 0.5 0.4 0.8 0.341 0.591 0.469 0.432 0.408 0.459 …
 $ M_index_pre3  : num  0.62 0.5 0.3 0.6 0.488 0.481 0.471 0.401 0.441 0.518 …
 $ HMMI_index_pre: num  0.646 0.5 0.416 0.727 0.451 …
 $ aux_index     : num  0.8 0.7 0.6 0.9 0.9 0.8 0.8 0.6 0.5 0.6 …
> summary(df[, c(“age”, “V_index_pre”, “T_index_pre”, “M_index_pre3”, “HMMI_index_pre”)])
      age        V_index_pre      T_index_pre      M_index_pre3    HMMI_index_pre  
 Min.   :10.0   Min.   :0.1890   Min.   :0.1410   Min.   :0.1150   Min.   :0.1923  
 1st Qu.:13.0   1st Qu.:0.5010   1st Qu.:0.4290   1st Qu.:0.4007   1st Qu.:0.4421  
 Median :14.0   Median :0.6060   Median :0.5285   Median :0.5115   Median :0.5414  
 Mean   :14.6   Mean   :0.6113   Mean   :0.5469   Mean   :0.5230   Mean   :0.5528  
 3rd Qu.:17.0   3rd Qu.:0.7043   3rd Qu.:0.6590   3rd Qu.:0.6302   3rd Qu.:0.6514  
 Max.   :18.0   Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.0000  
> table(df$condition, useNA = “ifany”)
 
adaptive  control  generic 
      39      131      110 
> table(df$gender, useNA = “ifany”)
 
      F   M 
  1 137 142 
> table(df$grade_group, useNA = “ifany”)
 
 5-8 9-11 
 168  112 
> # =========================================
> # 1. LOAD AND CLEAN DATA
> # =========================================
> library(dplyr)
> df <- read.csv(“/Users/vasylzalizko/Book2026.csv”,
+                sep = “;”,
+                stringsAsFactors = FALSE,
+                check.names = TRUE)
> # Перетворення десяткових ком на крапки
> to_num <- function(x) as.numeric(gsub(“,”, “.”, x, fixed = TRUE))
> num_cols <- c(“age”, “V_index_pre”, “T_index_pre”, “M_index_pre3”,
+               “HMMI_index_pre”, “HMMI_index_pre.1”)
> for (col in intersect(num_cols, names(df))) {
+     df[[col]] <- to_num(df[[col]])
+ }
> # Очищення категорій
> df$condition <- tolower(trimws(df$condition))
> df$grade_group <- trimws(df$grade_group)
> df$gender <- trimws(df$gender)
> # За потреби перейменувати дубльований стовпчик
> # Якщо ти знаєш, що HMMI_index_pre.1 = наприклад confidence_global або auxiliary score,
> # перейменуй його осмислено.
> names(df)[names(df) == “HMMI_index_pre.1”] <- “aux_index”
> # Перевірка
> str(df)
‘data.frame’: 280 obs. of  10 variables:
 $ learner_id    : chr  “S001” “S002” “S003” “S004” …
 $ grade_group   : chr  “5-8” “5-8” “5-8” “5-8” …
 $ condition     : chr  “control” “control” “control” “control” …
 $ age           : num  10 10 10 10 10 10 10 10 10 10 …
 $ gender        : chr  “F” “F” “F” “M” …
 $ V_index_pre   : num  0.67 0.5 0.6 0.8 0.553 0.662 0.511 0.544 0.341 0.561 …
 $ T_index_pre   : num  0.65 0.5 0.4 0.8 0.341 0.591 0.469 0.432 0.408 0.459 …
 $ M_index_pre3  : num  0.62 0.5 0.3 0.6 0.488 0.481 0.471 0.401 0.441 0.518 …
 $ HMMI_index_pre: num  0.646 0.5 0.416 0.727 0.451 …
 $ aux_index     : num  0.8 0.7 0.6 0.9 0.9 0.8 0.8 0.6 0.5 0.6 …
> summary(df[, c(“age”, “V_index_pre”, “T_index_pre”, “M_index_pre3”, “HMMI_index_pre”)])
      age        V_index_pre      T_index_pre      M_index_pre3    HMMI_index_pre  
 Min.   :10.0   Min.   :0.1890   Min.   :0.1410   Min.   :0.1150   Min.   :0.1923  
 1st Qu.:13.0   1st Qu.:0.5010   1st Qu.:0.4290   1st Qu.:0.4007   1st Qu.:0.4421  
 Median :14.0   Median :0.6060   Median :0.5285   Median :0.5115   Median :0.5414  
 Mean   :14.6   Mean   :0.6113   Mean   :0.5469   Mean   :0.5230   Mean   :0.5528  
 3rd Qu.:17.0   3rd Qu.:0.7043   3rd Qu.:0.6590   3rd Qu.:0.6302   3rd Qu.:0.6514  
 Max.   :18.0   Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.0000  
> table(df$condition, useNA = “ifany”)
 
adaptive  control  generic 
      39      131      110 
> table(df$gender, useNA = “ifany”)
 
      F   M 
  1 137 142 
> table(df$grade_group, useNA = “ifany”)
 
 5-8 9-11 
 168  112 
> library(ggplot2)
> ggplot(df, aes(x = gender, y = HMMI_index_pre)) +
+     geom_boxplot(width = 0.55) +
+     labs(
+         title = “Pretest HMMI by gender”,
+         x = “Gender”,
+         y = “HMMI (pretest)”
+     ) +
+     theme_minimal(base_size = 13)
> ggplot(df, aes(x = factor(age), y = HMMI_index_pre)) +
+     geom_boxplot(width = 0.6) +
+     labs(
+         title = “Pretest HMMI by age”,
+         x = “Age”,
+         y = “HMMI (pretest)”
+     ) +
+     theme_minimal(base_size = 13)
> library(tidyr)
> sub_long <- df %>%
+     select(gender, V_index_pre, T_index_pre, M_index_pre3) %>%
+     pivot_longer(cols = c(V_index_pre, T_index_pre, M_index_pre3),
+                  names_to = “Subindex”, values_to = “Value”)
> ggplot(sub_long, aes(x = gender, y = Value, fill = Subindex)) +
+     geom_boxplot() +
+     labs(
+         title = “Pretest subindices by gender”,
+         x = “Gender”,
+         y = “Subindex value”
+     ) +
+     theme_minimal(base_size = 13)
> # =========================================
> # 3. CORRELATION MAP
> # =========================================
> install.packages(“corrplot”)   # якщо ще не встановлено
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/corrplot_0.95.tgz’
Content type ‘application/x-gzip’ length 3828777 bytes (3.7 MB)
==================================================
downloaded 3.7 MB
 
 
The downloaded binary packages are in
/var/folders/n6/295fw91d3jz7qtpgw5zm41_r0000gn/T//RtmpxADw6P/downloaded_packages
> library(corrplot)
corrplot 0.95 loaded
> corr_data <- df %>%
+     select(age, V_index_pre, T_index_pre, M_index_pre3, HMMI_index_pre, aux_index) %>%
+     mutate(across(everything(), as.numeric))
> M <- cor(corr_data, use = “pairwise.complete.obs”)
> corrplot(M,
+          method = “color”,
+          type = “upper”,
+          order = “hclust”,
+          addCoef.col = “black”,
+          tl.col = “black”,
+          tl.srt = 35)
> # =========================================
> # 4. PCA + VISUALIZATION
> # =========================================
> install.packages(“factoextra”)   # якщо ще не встановлено
also installing the dependencies ‘later’, ‘otel’, ‘crosstalk’, ‘promises’, ‘viridis’, ‘DT’, ‘ellipse’, ‘flashClust’, ‘leaps’, ‘multcompView’, ‘scatterplot3d’, ‘cluster’, ‘dendextend’, ‘FactoMineR’, ‘ggpubr’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/later_1.4.8.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/otel_0.2.0.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/crosstalk_1.2.2.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/promises_1.5.0.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/viridis_0.6.5.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/DT_0.34.0.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/ellipse_0.5.0.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/flashClust_1.1-4.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/leaps_3.2.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/multcompView_0.1-11.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/scatterplot3d_0.3-45.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/cluster_2.1.8.2.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/dendextend_1.19.1.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/FactoMineR_2.13.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/ggpubr_0.6.3.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/factoextra_2.0.0.tgz’
 
The downloaded binary packages are in
/var/folders/n6/295fw91d3jz7qtpgw5zm41_r0000gn/T//RtmpxADw6P/downloaded_packages
> library(factoextra)
Welcome to factoextra!
Want to learn more? See two factoextra-related books at https://www.datanovia.com/en/product/practical-guide-to-principal-component-methods-in-r/
> pca_df <- df %>%
+     select(V_index_pre, T_index_pre, M_index_pre3, HMMI_index_pre, aux_index) %>%
+     mutate(across(everything(), as.numeric)) %>%
+     na.omit()
> res.pca <- prcomp(pca_df, center = TRUE, scale. = TRUE)
> # Внески змінних
> fviz_pca_var(res.pca,
+              col.var = “contrib”) +
+     ggplot2::theme_minimal()
> # Проекція учнів, пофарбована за статтю
> fviz_pca_ind(res.pca,
+              geom.ind = “point”,
+              habillage = df$gender[complete.cases(df[, c(“V_index_pre”,”T_index_pre”,”M_index_pre3″,”HMMI_index_pre”,”aux_index”)])],
+              addEllipses = TRUE) +
+     ggplot2::theme_minimal()
Too few points to calculate an ellipse
> visual–textual–mixed vulnerability
Error: unexpected input in “visual–”
 
> # =========================================
> # 5. GAM FOR NONLINEAR AGE EFFECTS
> # =========================================
> install.packages(“mgcv”)   # якщо треба
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/mgcv_1.9-4.tgz’
Content type ‘application/x-gzip’ length 4039913 bytes (3.9 MB)
==================================================
downloaded 3.9 MB
 
 
The downloaded binary packages are in
/var/folders/n6/295fw91d3jz7qtpgw5zm41_r0000gn/T//RtmpxADw6P/downloaded_packages
> library(mgcv)
Loading required package: nlme
 
Attaching package: ‘nlme’
 
The following object is masked from ‘package:dplyr’:
 
    collapse
 
The following object is masked from ‘package:lme4’:
 
    lmList
 
This is mgcv 1.9-4. For overview type ‘?mgcv’.
> # Для beta regression значення мають бути строго в (0,1)
> eps <- 0.001
> df$HMMI_beta <- pmin(pmax(df$HMMI_index_pre, eps), 1 – eps)
> m_gam <- gam(
+     HMMI_beta ~ s(age, k = 5) + gender + condition + grade_group,
+     data = df,
+     family = betar(link = “logit”),
+     method = “REML”
+ )
> summary(m_gam)
 
Family: Beta regression(10.264) 
Link function: logit 
 
Formula:
HMMI_beta ~ s(age, k = 5) + gender + condition + grade_group
 
Parametric coefficients:
                 Estimate Std. Error z value Pr(>|z|)  
(Intercept)       0.13776    0.61117   0.225   0.8217  
genderF          -0.15170    0.60133  -0.252   0.8008  
genderM           0.03296    0.60151   0.055   0.9563  
conditioncontrol  0.21124    0.11909   1.774   0.0761 .
conditiongeneric  0.25693    0.12155   2.114   0.0345 *
grade_group9-11  -0.06048    0.22112  -0.274   0.7844  
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
 
Approximate significance of smooth terms:
         edf Ref.df Chi.sq  p-value    
s(age) 3.181  3.649  41.82 8.43e-06 ***
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
 
R-sq.(adj) =  0.181   Deviance explained = 30.7%
-REML = -137.39  Scale est. = 1         n = 280
> plot(m_gam, pages = 1, residuals = TRUE, shade = TRUE)
> # =========================================
> # 6. AGE x GENDER INTERACTION VIA GAM
> # =========================================
> m_gam_int <- gam(
+     HMMI_beta ~ gender + condition + grade_group +
+         s(age, k = 5) +
+         s(age, by = gender, k = 5),
+     data = df,
+     family = betar(link = “logit”),
+     method = “REML”
+ )
Error in smoothCon(split$smooth.spec[[i]], data, knots, absorb.cons, scale.penalty = scale.penalty,  : 
  Can’t find by variable
 
> # =========================================
> # 7. LINEAR INTERACTION MODEL + SIMPLE SLOPES
> # =========================================
> install.packages(“interactions”)   # якщо треба
also installing the dependencies ‘listenv’, ‘parallelly’, ‘future’, ‘globals’, ‘furrr’, ‘broom.mixed’, ‘pander’, ‘jtools’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/listenv_0.10.1.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/parallelly_1.46.1.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/future_1.70.0.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/globals_0.19.1.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/furrr_0.3.1.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/broom.mixed_0.2.9.7.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/pander_0.6.6.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/jtools_2.3.1.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/interactions_1.2.0.tgz’
 
The downloaded binary packages are in
/var/folders/n6/295fw91d3jz7qtpgw5zm41_r0000gn/T//RtmpxADw6P/downloaded_packages
> library(interactions)
> m_lm <- lm(
+     HMMI_index_pre ~ age * gender + condition + grade_group,
+     data = df
+ )
> summary(m_lm)
 
Call:
lm(formula = HMMI_index_pre ~ age * gender + condition + grade_group, 
    data = df)
 
Residuals:
     Min       1Q   Median       3Q      Max 
-0.34109 -0.08755  0.00350  0.08930  0.41557 
 
Coefficients: (1 not defined because of singularities)
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)       0.059327   0.178170   0.333  0.73941    
age               0.033897   0.008008   4.233 3.16e-05 ***
genderF           0.262923   0.169871   1.548  0.12284    
genderM          -0.011298   0.133196  -0.085  0.93246    
conditioncontrol  0.010777   0.026051   0.414  0.67942    
conditiongeneric  0.032176   0.026554   1.212  0.22668    
grade_group9-11   0.023573   0.031773   0.742  0.45876    
age:genderF      -0.021239   0.007436  -2.856  0.00462 ** 
age:genderM             NA         NA      NA       NA    
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
 
Residual standard error: 0.132 on 272 degrees of freedom
Multiple R-squared:  0.2147, Adjusted R-squared:  0.1945 
F-statistic: 10.62 on 7 and 272 DF,  p-value: 8.152e-12
 
> interact_plot(m_lm,
+               pred = age,
+               modx = gender,
+               interval = TRUE,
+               plot.points = TRUE)
Warning message:
In predict.lm(model, newdata = pm, se.fit = interval, interval = int.type[1],  :
  prediction from rank-deficient fit; attr(*, “non-estim”) has doubtful cases
> johnson_neyman(m_lm, pred = age, modx = gender)
Error in `johnson_neyman()`:
! Could not find interaction term in the model, so Johnson-Neyman interval could not be
calculated.
Backtrace:
 1. interactions::johnson_neyman(m_lm, pred = age, modx = gender)
 
> # =========================================
> # 8. K-MEANS CLUSTERING OF LEARNER PROFILES
> # =========================================
> cluster_df <- df %>%
+     select(V_index_pre, T_index_pre, M_index_pre3, HMMI_index_pre) %>%
+     mutate(across(everything(), as.numeric)) %>%
+     na.omit()
> set.seed(123)
> km3 <- kmeans(scale(cluster_df), centers = 3, nstart = 25)
> df_clusters <- df %>%
+     filter(complete.cases(select(., V_index_pre, T_index_pre, M_index_pre3, HMMI_index_pre))) %>%
+     mutate(cluster = factor(km3$cluster))
> # Подивитися середні профілі кластерів
> df_clusters %>%
+     group_by(cluster) %>%
+     summarise(
+         V = mean(V_index_pre, na.rm = TRUE),
+         T = mean(T_index_pre, na.rm = TRUE),
+         M = mean(M_index_pre3, na.rm = TRUE),
+         HMMI = mean(HMMI_index_pre, na.rm = TRUE),
+         n = n()
+     )
# A tibble: 3 × 6
  cluster     V     T     M  HMMI     n
  <fct>   <dbl> <dbl> <dbl> <dbl> <int>
1 1       0.628 0.560 0.547 0.572   118
2 2       0.487 0.403 0.367 0.406   102
3 3       0.791 0.766 0.741 0.763    60
> V = mean(V_index_pre, na.rm = TRUE),
Error: unexpected ‘,’ in “V = mean(V_index_pre, na.rm = TRUE),”
 
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> cluster_profile <- df_clusters %>%
+     group_by(cluster) %>%
+     summarise(
+         Visual = mean(V_index_pre, na.rm = TRUE),
+         Textual = mean(T_index_pre, na.rm = TRUE),
+         Mixed = mean(M_index_pre3, na.rm = TRUE),
+         HMMI = mean(HMMI_index_pre, na.rm = TRUE),
+         .groups = “drop”
+     ) %>%
+     pivot_longer(cols = c(Visual, Textual, Mixed, HMMI),
+                  names_to = “Metric”, values_to = “Value”)
> p_cluster <- ggplot(cluster_profile,
+                     aes(x = Metric, y = Value, group = cluster, linetype = cluster)) +
+     geom_line(linewidth = 1) +
+     geom_point(size = 2) +
+     labs(
+         title = “Latent cognitive-vulnerability profiles”,
+         x = NULL,
+         y = “Mean value”
+     ) +
+     theme_minimal(base_size = 13)
> print(p_cluster)
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> cluster_profile <- df_clusters %>%
+     group_by(cluster) %>%
+     summarise(
+         Visual = mean(V_index_pre, na.rm = TRUE),
+         Textual = mean(T_index_pre, na.rm = TRUE),
+         Mixed = mean(M_index_pre3, na.rm = TRUE),
+         HMMI = mean(HMMI_index_pre, na.rm = TRUE),
+         .groups = “drop”
+     ) %>%
+     pivot_longer(cols = c(Visual, Textual, Mixed, HMMI),
+                  names_to = “Metric”, values_to = “Value”)
> p_cluster_bar <- ggplot(cluster_profile,
+                         aes(x = Metric, y = Value, fill = cluster)) +
+     geom_col(position = “dodge”, width = 0.72) +
+     labs(
+         title = “Latent cognitive-vulnerability profiles”,
+         x = NULL,
+         y = “Mean value”
+     ) +
+     theme_minimal(base_size = 13)
> print(p_cluster_bar)
> # Якщо бібліотеки не встановлені, розкоментуйте наступні рядки:
> # install.packages(c(“ggplot2”, “dplyr”, “randomForest”, “corrr”, “patchwork”))
> library(ggplot2)
> library(dplyr)
> library(randomForest)
Error in library(randomForest) : 
  there is no package called ‘randomForest’
 
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> # —————————————-
> # 1. Якщо post-індекс ще не порахований
> # —————————————-
> df$HMMI_index_post <- (df$V_index_post * df$T_index_post * df$M_index_post)^(1/3)
Error in `$<-.data.frame`(`*tmp*`, HMMI_index_post, value = numeric(0)) : 
  replacement has 0 rows, data has 280
 
> # Якщо HMMI_index_post ще не існує
> df$HMMI_index_post <- (df$V_index_post * df$T_index_post * df$M_index_post)^(1/3)
Error in `$<-.data.frame`(`*tmp*`, HMMI_index_post, value = numeric(0)) : 
  replacement has 0 rows, data has 280
 
> install.packages(“randomForest”)
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/randomForest_4.7-1.2.tgz’
Content type ‘application/x-gzip’ length 260492 bytes (254 KB)
==================================================
downloaded 254 KB
 
 
The downloaded binary packages are in
/var/folders/n6/295fw91d3jz7qtpgw5zm41_r0000gn/T//RtmpxADw6P/downloaded_packages
> # Список необхідних пакетів
> packages <- c(“ggplot2”, “dplyr”, “randomForest”, “corrplot”, “RColorBrewer”)
> # Автоматичне встановлення та завантаження
> for (p in packages) {
+     if (!require(p, character.only = TRUE)) {
+         install.packages(p)
+         library(p, character.only = TRUE)
+     }
+ }
Loading required package: randomForest
randomForest 4.7-1.2
Type rfNews() to see new features/changes/bug fixes.
 
Attaching package: ‘randomForest’
 
The following object is masked from ‘package:gridExtra’:
 
    combine
 
The following object is masked from ‘package:dplyr’:
 
    combine
 
The following object is masked from ‘package:ggplot2’:
 
    margin
 
Loading required package: RColorBrewer
> # Читання вашого файлу Book2026.csv
> # Використовуйте file.choose() для Mac, щоб знайти файл вручну
> df <- read.csv(file.choose(), sep = “;”, dec = “,”)
> # — РИСУНОК 1: ВАЖЛИВІСТЬ ЗМІННИХ (Random Forest) —
> # Визначаємо, що найбільше впливає на результат (HMMI)
> rf_model <- randomForest(HMMI_index_pre ~ age + condition + V_index_pre + T_index_pre, 
+                          data = df, importance = TRUE)
> varImpPlot(rf_model, main = “Variable Importance in Cognitive Modeling”)
> # — РИСУНОК 2: ВІКОВА ДИНАМІКА —
> ggplot(df, aes(x = as.factor(age), y = HMMI_index_pre, fill = condition)) +
+     geom_boxplot(alpha = 0.7) +
+     theme_minimal() +
+     labs(title = “HMMI Score by Age and Condition”, x = “Age”, y = “HMMI Index”)
> # — РИСУНОК 3: КОРЕЛЯЦІЙНА МАТРИЦЯ —
> corr_data <- cor(df[, c(“V_index_pre”, “T_index_pre”, “M_index_pre3”, “HMMI_index_pre”)], use=”complete.obs”)
> corrplot(corr_data, method = “color”, addCoef.col = “black”, tl.col = “black”, 
+          col = brewer.pal(n = 8, name = “RdYlBu”), title = “Cognitive Indices Correlation”)
> # Список необхідних пакетів
> packages <- c(“ggplot2”, “dplyr”, “randomForest”, “corrplot”, “RColorBrewer”)
> # Автоматичне встановлення та завантаження
> for (p in packages) {
+     if (!require(p, character.only = TRUE)) {
+         install.packages(p)
+         library(p, character.only = TRUE)
+     }
+ }
> # Читання вашого файлу Book2026.csv
> # Використовуйте file.choose() для Mac, щоб знайти файл вручну
> df <- read.csv(file.choose(), sep = “;”, dec = “,”)
> # — РИСУНОК 1: ВАЖЛИВІСТЬ ЗМІННИХ (Random Forest) —
> # Визначаємо, що найбільше впливає на результат (HMMI)
> rf_model <- randomForest(HMMI_index_pre ~ age + condition + V_index_pre + T_index_pre, 
+                          data = df, importance = TRUE)
> varImpPlot(rf_model, main = “Variable Importance in Cognitive Modeling”)
> # — РИСУНОК 2: ВІКОВА ДИНАМІКА —
> ggplot(df, aes(x = as.factor(age), y = HMMI_index_pre, fill = condition)) +
+     geom_boxplot(alpha = 0.7) +
+     theme_minimal() +
+     labs(title = “HMMI Score by Age and Condition”, x = “Age”, y = “HMMI Index”)
> # — РИСУНОК 3: КОРЕЛЯЦІЙНА МАТРИЦЯ —
> corr_data <- cor(df[, c(“V_index_pre”, “T_index_pre”, “M_index_pre3”, “HMMI_index_pre”)], use=”complete.obs”)
> corrplot(corr_data, method = “color”, addCoef.col = “black”, tl.col = “black”, 
+          col = brewer.pal(n = 8, name = “RdYlBu”), title = “Cognitive Indices Correlation”)
> # 1. СТВОРЕННЯ МОДЕЛІ ПОРІВНЯННЯ (Pre vs Post)
> # Якщо у вас у файлі Post-тест називається інакше, замініть назву.
> # Для прикладу ми порівняємо базовий T_index_pre та результуючий HMMI_index_pre.
> library(tidyr)
> library(ggplot2)
> library(dplyr)
> # Трансформуємо дані для порівняння (Long format)
> df_comparison <- df %>%
+     select(learner_id, age, condition, T_index_pre, HMMI_index_pre) %>%
+     rename(Baseline = T_index_pre, Impact_Result = HMMI_index_pre) %>%
+     pivot_longer(cols = c(Baseline, Impact_Result), 
+                  names_to = “Timepoint”, 
+                  values_to = “Score”)
> # ГРАФІК 1: ПЕРЕД І ПІСЛЯ (Slope Graph за віком)
> # Показує, чи впав результат учня після зіткнення з контентом
> ggplot(df_comparison, aes(x = Timepoint, y = Score, group = learner_id, color = condition)) +
+     geom_line(alpha = 0.2) +
+     geom_point(alpha = 0.5) +
+     facet_wrap(~age) +
+     theme_minimal() +
+     labs(title = “Figure 1: Transition from Baseline to Impact Result by Age”,
+          subtitle = “Modeling the cognitive shift in the Digital Twin”)
> # ГРАФІК 2: ДЕЛЬТА (Різниця між Pre та Post)
> # Чим нижче точка, тим більше “шкоди” завдав маніпулятивний графік
> df$Learning_Gain <- df$HMMI_index_pre – df$T_index_pre
> ggplot(df, aes(x = as.factor(age), y = Learning_Gain, fill = condition)) +
+     geom_hline(yintercept = 0, linetype = “dashed”, color = “red”) +
+     geom_boxplot() +
+     labs(title = “Figure 2: Cognitive Impact Magnitude (Post minus Pre)”,
+          x = “Age”, y = “Change in Performance Score”)
> # ГРАФІК 3: ПОРІВНЯННЯ СЕРЕДНІХ (Bar Chart з помилками)
> # Ідеально для демонстрації того, як Digital Twin мінімізує падіння результату
> df_summary <- df_comparison %>%
+     group_by(Timepoint, condition) %>%
+     summarise(Mean = mean(Score), SD = sd(Score))
`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by Timepoint and condition.
ℹ Output is grouped by Timepoint.
ℹ Use `summarise(.groups = “drop_last”)` to silence this message.
ℹ Use `summarise(.by = c(Timepoint, condition))` for per-operation grouping instead.
> ggplot(df_summary, aes(x = condition, y = Mean, fill = Timepoint)) +
+     geom_bar(stat = “identity”, position = position_dodge()) +
+     geom_errorbar(aes(ymin = Mean-SD, ymax = Mean+SD), width = .2, position = position_dodge(.9)) +
+     scale_fill_manual(values = c(“#69b3a2”, “#404080”)) +
+     labs(title = “Figure 3: Mean Score Degradation: Baseline vs. Post-Impact”)
> # Встановлення необхідних пакетів
> if (!require(“tidyverse”)) install.packages(“tidyverse”)
> library(tidyverse)
> # Завантаження файлу
> df <- read.csv(file.choose(), sep = “;”, dec = “,”)
> # Створюємо “чистий” набір для порівняння Pre vs Post
> df_long <- df %>%
+     select(learner_id, age, condition, T_index_pre, HMMI_index_pre) %>%
+     rename(Pre_Index = T_index_pre, Post_Index = HMMI_index_pre) %>%
+     pivot_longer(cols = c(Pre_Index, Post_Index), 
+                  names_to = “Stage”, 
+                  values_to = “Score”) %>%
+     mutate(Stage = factor(Stage, levels = c(“Pre_Index”, “Post_Index”)))
> ggplot(df_long, aes(x = Stage, y = Score, group = learner_id, color = condition)) +
+     geom_line(alpha = 0.3, size = 0.5) +
+     geom_point(alpha = 0.4) +
+     facet_wrap(~condition) +
+     scale_color_brewer(palette = “Set1”) +
+     theme_minimal() +
+     labs(title = “Individual Cognitive Shifts: Pre vs. Post”,
+          subtitle = “Visualizing the impact of misleading information per student”)
Warning message:
Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
This warning is displayed once per session.
Call lifecycle::last_lifecycle_warnings() to see where this warning was generated. 
 
> df <- df %>% mutate(Delta = HMMI_index_pre – T_index_pre)
> ggplot(df, aes(x = as.factor(age), y = Delta, fill = condition)) +
+     geom_hline(yintercept = 0, linetype = “dashed”, color = “black”) +
+     geom_boxplot(outlier.alpha = 0.5) +
+     theme_classic() +
+     labs(title = “Learning Gain/Loss Across Age Groups”,
+          x = “Age”, y = “Score Delta (Post – Pre)”)
> df_summary <- df_long %>%
+     group_by(Stage, condition) %>%
+     summarise(MeanScore = mean(Score), SEM = sd(Score)/sqrt(n()))
`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by Stage and condition.
ℹ Output is grouped by Stage.
ℹ Use `summarise(.groups = “drop_last”)` to silence this message.
ℹ Use `summarise(.by = c(Stage, condition))` for per-operation grouping instead.
> ggplot(df_summary, aes(x = condition, y = MeanScore, fill = Stage)) +
+     geom_bar(stat = “identity”, position = position_dodge()) +
+     geom_errorbar(aes(ymin = MeanScore – SEM, ymax = MeanScore + SEM), 
+                   width = .2, position = position_dodge(.9)) +
+     theme_bw() +
+     labs(title = “Mean Performance: Baseline vs. Post-Impact Result”,
+          y = “Mean Score Index”)
> library(ggplot2)
> # Порівняння розподілів
> ggplot(df_long, aes(x = Score, fill = Stage)) +
+     geom_density(alpha = 0.5) +
+     facet_wrap(~condition) +
+     theme_minimal() +
+     labs(title = “Cognitive Index Distribution Shift”,
+          x = “Index Value”, y = “Density”)
> “/Users/vasylzalizko/Book2026.csv”
[1] “/Users/vasylzalizko/Book2026.csv”
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> library(patchwork)
> # —————————–
> # Load data
> # —————————–
> df <- read.csv(“/Users/vasylzalizko/Book2026.csv”,
+                sep = “;”,
+                stringsAsFactors = FALSE,
+                check.names = TRUE)
> to_num <- function(x) as.numeric(gsub(“,”, “.”, x, fixed = TRUE))
> num_cols <- c(“age”, “V_index_pre”, “T_index_pre”, “M_index_pre3”,
+               “HMMI_index_pre”, “HMMI_index_post”)
> for (col in num_cols) {
+     if (col %in% names(df)) df[[col]] <- to_num(df[[col]])
+ }
> df$condition   <- tolower(trimws(df$condition))
> df$grade_group <- trimws(df$grade_group)
> df$gender      <- trimws(df$gender)
> # Change score
> df$delta_hmmi <- df$HMMI_index_post – df$HMMI_index_pre
> # Quick checks
> summary(df[, c(“HMMI_index_pre”, “HMMI_index_post”, “delta_hmmi”)])
 HMMI_index_pre   HMMI_index_post    delta_hmmi      
 Min.   :0.1923   Min.   :0.3000   Min.   :-0.30000  
 1st Qu.:0.4421   1st Qu.:0.6000   1st Qu.: 0.06397  
 Median :0.5414   Median :0.8000   Median : 0.22251  
 Mean   :0.5528   Mean   :0.7732   Mean   : 0.22037  
 3rd Qu.:0.6514   3rd Qu.:0.9000   3rd Qu.: 0.35240  
 Max.   :1.0000   Max.   :1.0000   Max.   : 0.70773  
> table(df$condition)
 
adaptive  control  generic 
      39      131      110 
> table(df$grade_group)
 
 5-8 9-11 
 168  112 
> table(df$gender)
 
      F   M 
  1 137 142 
> fig1_df <- df %>%
+     group_by(condition) %>%
+     summarise(
+         pre  = mean(HMMI_index_pre, na.rm = TRUE),
+         post = mean(HMMI_index_post, na.rm = TRUE),
+         .groups = “drop”
+     ) %>%
+     pivot_longer(cols = c(pre, post), names_to = “phase”, values_to = “HMMI”)
> p1 <- ggplot(fig1_df, aes(x = condition, y = HMMI, fill = phase)) +
+     geom_col(position = “dodge”, width = 0.72) +
+     labs(
+         title = “Pretest and posttest HMMI across instructional conditions”,
+         subtitle = “Comparison of control, generic support, and adaptive digital-twin-guided support”,
+         x = NULL,
+         y = “Mean HMMI”
+     ) +
+     theme_minimal(base_size = 13)
> print(p1)
> fig1_df <- df %>%
+     group_by(condition) %>%
+     summarise(
+         pre  = mean(HMMI_index_pre, na.rm = TRUE),
+         post = mean(HMMI_index_post, na.rm = TRUE),
+         .groups = “drop”
+     ) %>%
+     pivot_longer(cols = c(pre, post), names_to = “phase”, values_to = “HMMI”)
> p1 <- ggplot(fig1_df, aes(x = condition, y = HMMI, fill = phase)) +
+     geom_col(position = “dodge”, width = 0.72) +
+     labs(
+         title = “Pretest and posttest HMMI across instructional conditions”,
+         subtitle = “Comparison of control, generic support, and adaptive digital-twin-guided support”,
+         x = NULL,
+         y = “Mean HMMI”
+     ) +
+     theme_minimal(base_size = 13)
> print(p1)
> # 1. Підготовка даних (якщо ще не зроблено)
> library(ggplot2)
> library(dplyr)
> library(tidyr)
> # Завантажуємо дані
> df <- read.csv(file.choose(), sep = “;”, dec = “,”)
> # Створюємо довгий формат для порівняння
> df_long <- df %>%
+     select(learner_id, condition, age, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(cols = c(HMMI_index_pre, HMMI_index_post), 
+                  names_to = “Timepoint”, values_to = “Score”)
> # 2. ВІДКРИВАЄМО ПРИСТРІЙ ЗАПИСУ (Створюємо багатосторінковий PDF)
> pdf(“DigitalTwin_Results_2026.pdf”, width = 8, height = 6)
> # Графік 1: Індивідуальний прогрес (Slope Graph)
> p1 <- ggplot(df_long, aes(x = Timepoint, y = Score, group = learner_id, color = condition)) +
+     geom_line(alpha = 0.3) +
+     geom_point(alpha = 0.5) +
+     facet_wrap(~condition) +
+     theme_minimal() +
+     labs(title = “Individual Learning Progress: Pre vs Post”)
> print(p1)
> # Графік 2: Приріст знань (Learning Gain)
> df$Gain <- df$HMMI_index_post – df$HMMI_index_pre
> p2 <- ggplot(df, aes(x = condition, y = Gain, fill = condition)) +
+     geom_boxplot() +
+     theme_classic() +
+     labs(title = “Distribution of Learning Gains”)
> print(p2)
> # Графік 3: Вікова залежність Post-результату
> p3 <- ggplot(df, aes(x = age, y = HMMI_index_post, color = condition)) +
+     geom_jitter(alpha = 0.4) +
+     geom_smooth(method = “loess”) +
+     theme_light() +
+     labs(title = “Post-Learning Success across Age Groups”)
> print(p3)
`geom_smooth()` using formula = ‘y ~ x’
Warning messages:
1: In simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  at  13.98
2: In simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  radius  0.0004
3: In simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  all data on boundary of neighborhood. make span bigger
4: In simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  pseudoinverse used at 13.98
5: In simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  neighborhood radius 0.02
6: In simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  reciprocal condition number  1
7: In simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  There are other near singularities as well. 16.16
8: In simpleLoess(y, x, w, span, degree = degree, parametric = parametric,  :
  zero-width neighborhood. make span bigger
9: Failed to fit group 1.
Caused by error in `predLoess()`:
! NA/NaN/Inf in foreign function call (arg 5) 
> # 3. ЗАКРИВАЄМО ПРИСТРІЙ (Обов’язково!)
> dev.off()
RStudioGD 
        2 
> cat(“Всі графіки збережені у файл: DigitalTwin_Results_2026.pdf у вашій директорії:”, getwd())
Всі графіки збережені у файл: DigitalTwin_Results_2026.pdf у вашій директорії: /Users/vasylzalizko
> давай окремими pngфайлами! 8 основних характеристик!
Error: unexpected symbol in “давай окремими”
 
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> # —————————–
> # Load data
> # —————————–
> df <- read.csv(“/Users/vasylzalizko/Book2026.csv”,
+                sep = “;”,
+                stringsAsFactors = FALSE,
+                check.names = TRUE)
> # —————————–
> # Convert decimal commas
> # —————————–
> to_num <- function(x) as.numeric(gsub(“,”, “.”, x, fixed = TRUE))
> # If post column is still duplicated incorrectly, fix it
> if (!(“HMMI_index_post” %in% names(df)) && (“HMMI_index_pre.1” %in% names(df))) {
+     names(df)[names(df) == “HMMI_index_pre.1”] <- “HMMI_index_post”
+ }
> # Numeric columns
> num_cols <- c(“age”, “V_index_pre”, “T_index_pre”, “M_index_pre3”,
+               “HMMI_index_pre”, “HMMI_index_post”)
> for (col in num_cols) {
+     if (col %in% names(df)) df[[col]] <- to_num(df[[col]])
+ }
> # Clean categories
> df$condition   <- tolower(trimws(df$condition))
> df$grade_group <- trimws(df$grade_group)
> df$gender      <- trimws(df$gender)
> # Delta
> df$delta_hmmi <- df$HMMI_index_post – df$HMMI_index_pre
> # Check
> names(df)
 [1] “learner_id”      “grade_group”     “condition”       “age”            
 [5] “gender”          “V_index_pre”     “T_index_pre”     “M_index_pre3”   
 [9] “HMMI_index_pre”  “HMMI_index_post” “delta_hmmi”     
> summary(df[, c(“HMMI_index_pre”, “HMMI_index_post”, “delta_hmmi”)])
 HMMI_index_pre   HMMI_index_post    delta_hmmi      
 Min.   :0.1923   Min.   :0.3000   Min.   :-0.30000  
 1st Qu.:0.4421   1st Qu.:0.6000   1st Qu.: 0.06397  
 Median :0.5414   Median :0.8000   Median : 0.22251  
 Mean   :0.5528   Mean   :0.7732   Mean   : 0.22037  
 3rd Qu.:0.6514   3rd Qu.:0.9000   3rd Qu.: 0.35240  
 Max.   :1.0000   Max.   :1.0000   Max.   : 0.70773  
> table(df$condition)
 
adaptive  control  generic 
      39      131      110 
> table(df$gender)
 
      F   M 
  1 137 142 
> fig1_df <- df %>%
+     group_by(condition) %>%
+     summarise(
+         pre  = mean(HMMI_index_pre, na.rm = TRUE),
+         post = mean(HMMI_index_post, na.rm = TRUE),
+         .groups = “drop”
+     ) %>%
+     pivot_longer(cols = c(pre, post), names_to = “phase”, values_to = “HMMI”)
> p1 <- ggplot(fig1_df, aes(x = condition, y = HMMI, fill = phase)) +
+     geom_col(position = “dodge”, width = 0.72) +
+     labs(
+         title = “Pretest and posttest HMMI across instructional conditions”,
+         subtitle = “Control, generic support, and adaptive digital-twin-guided support”,
+         x = NULL,
+         y = “Mean HMMI”
+     ) +
+     theme_minimal(base_size = 13)
> ggsave(“figure1_pre_post_hmmi_by_condition.png”, p1, width = 7.5, height = 4.8, dpi = 300)
> p1
> fig2_df <- df %>%
+     filter(condition == “control”) %>%
+     group_by(age) %>%
+     summarise(
+         HMMI_pre  = mean(HMMI_index_pre, na.rm = TRUE),
+         HMMI_post = mean(HMMI_index_post, na.rm = TRUE),
+         .groups = “drop”
+     ) %>%
+     mutate(age = factor(age))
> p2 <- ggplot(fig2_df) +
+     geom_segment(aes(x = HMMI_pre, xend = HMMI_post, y = age, yend = age), linewidth = 1.4) +
+     geom_point(aes(x = HMMI_pre, y = age), size = 2.8, shape = 16) +
+     geom_point(aes(x = HMMI_post, y = age), size = 2.8, shape = 17) +
+     labs(
+         title = “Pre-post HMMI by age: control group”,
+         subtitle = “Circles = pretest, triangles = posttest”,
+         x = “Mean HMMI”,
+         y = “Age”
+     ) +
+     theme_minimal(base_size = 13)
> ggsave(“figure2_pre_post_hmmi_by_age_control.png”, p2, width = 7.8, height = 5.0, dpi = 300)
> p2
> fig1_df <- df %>%
+     group_by(condition) %>%
+     summarise(
+         pre  = mean(HMMI_index_pre, na.rm = TRUE),
+         post = mean(HMMI_index_post, na.rm = TRUE),
+         .groups = “drop”
+     ) %>%
+     pivot_longer(cols = c(pre, post), names_to = “phase”, values_to = “HMMI”)
> p1 <- ggplot(fig1_df, aes(x = condition, y = HMMI, fill = phase)) +
+     geom_col(position = “dodge”, width = 0.72) +
+     labs(
+         title = “Pretest and posttest HMMI across instructional conditions”,
+         subtitle = “Control, generic support, and adaptive digital-twin-guided support”,
+         x = NULL,
+         y = “Mean HMMI”
+     ) +
+     theme_minimal(base_size = 13)
> ggsave(“figure1_pre_post_hmmi_by_condition.png”, p1, width = 7.5, height = 4.8, dpi = 300)
> p1
> df <- read.csv(“/Users/vasylzalizko/Book2026.csv”,
+                sep = “;”,
+                stringsAsFactors = FALSE,
+                check.names = TRUE)
> to_num <- function(x) as.numeric(gsub(“,”, “.”, x, fixed = TRUE))
> if (!(“HMMI_index_post” %in% names(df)) && (“HMMI_index_pre.1” %in% names(df))) {
+     names(df)[names(df) == “HMMI_index_pre.1”] <- “HMMI_index_post”
+ }
> num_cols <- c(“age”, “V_index_pre”, “T_index_pre”, “M_index_pre3”,
+               “HMMI_index_pre”, “HMMI_index_post”)
> for (col in num_cols) {
+     if (col %in% names(df)) df[[col]] <- to_num(df[[col]])
+ }
> df$condition   <- tolower(trimws(df$condition))
> df$grade_group <- trimws(df$grade_group)
> df$gender      <- trimws(df$gender)
> # Якщо хочеш improvement = positive
> df$delta_hmmi <- df$HMMI_index_pre – df$HMMI_index_post
> fig1_df <- df %>%
+     select(condition, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(cols = c(HMMI_index_pre, HMMI_index_post),
+                  names_to = “phase”, values_to = “HMMI”)
> fig1_df$phase <- recode(fig1_df$phase,
+                         HMMI_index_pre = “Pretest”,
+                         HMMI_index_post = “Posttest”)
> p1 <- ggplot(fig1_df, aes(x = HMMI, linetype = phase)) +
+     geom_density(linewidth = 1.1) +
+     facet_wrap(~ condition, nrow = 1) +
+     labs(
+         title = “Distributional shift of HMMI from pretest to posttest”,
+         subtitle = “Gaussian-like density lines across instructional conditions”,
+         x = “HMMI”,
+         y = “Density”
+     ) +
+     theme_minimal(base_size = 13)
> ggsave(“figure1_density_pre_post_by_condition.png”, p1, width = 10, height = 4.8, dpi = 300)
> p1
> p2 < 99plot(df, aes (x = HMMI_index_pre, y = factor(age), height = after_stat(density)))
Error: unexpected symbol in “p2 < 99plot”
 
> library(ggplot2)
> library(dplyr)
> library(tidyr)
> # 1. Завантаження та підготовка даних
> df <- read.csv(file.choose(), sep = “;”, dec = “,”)
> # Перетворюємо у довгий формат для ggplot
> df_density <- df %>%
+     select(condition, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(cols = starts_with(“HMMI”), 
+                  names_to = “Stage”, 
+                  values_to = “Value”) %>%
+     mutate(Stage = factor(Stage, 
+                           levels = c(“HMMI_index_pre”, “HMMI_index_post”),
+                           labels = c(“Initial (Pre)”, “Final (Post)”)))
> # 2. Побудова графіка з кривими Гаусса (Density Plot)
> ggplot(df_density, aes(x = Value, fill = Stage)) +
+     # geom_density створює плавні криві розподілу
+     geom_density(alpha = 0.5, color = “white”) + 
+     # Розділяємо на панелі за умовами (Control, Generic, Adaptive)
+     facet_wrap(~condition) + 
+     scale_fill_manual(values = c(“#3498db”, “#2ecc71”)) + # Синій для Pre, Зелений для Post
+     theme_minimal() +
+     labs(title = “Gaussian Distribution Shift: Pre vs Post Learning Stage”,
+          subtitle = “Shift to the right indicates cognitive growth (HMMI)”,
+          x = “Cognitive Index Score”, 
+          y = “Density”,
+          fill = “Learning Stage”) +
+     theme(legend.position = “bottom”,
+           strip.text = element_text(size = 12, face = “bold”))
> # 3. Збереження для LaTeX
> ggsave(“Gaussian_Shift_HMMI.pdf”, width = 10, height = 6)
> p2 <- ggplot(df, aes(x = HMMI_index_pre, y = factor(age), height = after_stat(density))) +
+     geom_density_ridges(stat = “density”, alpha = 0.6, scale = 1.2) +
+     facet_wrap(~ condition, nrow = 1) +
+     labs(
+         title = “Pretest HMMI across age groups and conditions”,
+         x = “HMMI (pretest)”,
+         y = “Age”
+     ) +
+     theme_minimal(base_size = 13)
Error in geom_density_ridges(stat = “density”, alpha = 0.6, scale = 1.2) : 
  could not find function “geom_density_ridges”
 
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> fig1_df <- df %>%
+     select(condition, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(cols = c(HMMI_index_pre, HMMI_index_post),
+                  names_to = “phase”, values_to = “HMMI”)
> fig1_df$phase <- recode(fig1_df$phase,
+                         HMMI_index_pre = “Pretest”,
+                         HMMI_index_post = “Posttest”)
> fig1_df$condition <- factor(fig1_df$condition,
+                             levels = c(“control”, “generic”, “adaptive”),
+                             labels = c(“Control”, “Generic support”, “Adaptive digital twin”))
> p1_new <- ggplot(fig1_df, aes(x = HMMI, fill = phase, color = phase)) +
+     geom_density(alpha = 0.28, linewidth = 1.1, adjust = 1.1) +
+     facet_wrap(~ condition, nrow = 1) +
+     scale_fill_manual(values = c(“Pretest” = “#4C78A8”, “Posttest” = “#E45756”)) +
+     scale_color_manual(values = c(“Pretest” = “#4C78A8”, “Posttest” = “#E45756”)) +
+     labs(
+         title = “Distributional shift of learner vulnerability from pretest to posttest”,
+         subtitle = “Human Multimodal Misleadingness Index (HMMI) across instructional conditions”,
+         x = “HMMI”,
+         y = “Density”
+     ) +
+     theme_minimal(base_size = 14) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         strip.text = element_text(face = “bold”),
+         legend.position = “top”
+     )
> ggsave(“figure1_density_pre_post_colored.png”, p1_new, width = 10.5, height = 5.2, dpi = 300)
> p1_new
> med_df <- fig1_df %>%
+     group_by(condition, phase) %>%
+     summarise(med = median(HMMI, na.rm = TRUE), .groups = “drop”)
> p1_med <- ggplot(fig1_df, aes(x = HMMI, fill = phase, color = phase)) +
+     geom_density(alpha = 0.25, linewidth = 1.15, adjust = 1.1) +
+     geom_vline(data = med_df, aes(xintercept = med, color = phase),
+                linetype = “dashed”, linewidth = 0.9, show.legend = FALSE) +
+     facet_wrap(~ condition, nrow = 1) +
+     scale_fill_manual(values = c(“Pretest” = “#4C78A8”, “Posttest” = “#E45756”)) +
+     scale_color_manual(values = c(“Pretest” = “#4C78A8”, “Posttest” = “#E45756”)) +
+     labs(
+         title = “Distributional shift of HMMI from pretest to posttest”,
+         subtitle = “Dashed lines indicate median values within each instructional condition”,
+         x = “HMMI”,
+         y = “Density”
+     ) +
+     theme_minimal(base_size = 14) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         strip.text = element_text(face = “bold”),
+         legend.position = “top”
+     )
> ggsave(“figure1_density_pre_post_medians.png”, p1_med, width = 10.8, height = 5.3, dpi = 300)
> p1_med
> library(ggdist)
Error in library(ggdist) : there is no package called ‘ggdist’
 
> library(dplyr)
> df <- read.csv(“/Users/vasylzalizko/Book2026.csv”,
+                sep = “;”,
+                stringsAsFactors = FALSE,
+                check.names = TRUE)
> to_num <- function(x) as.numeric(gsub(“,”, “.”, x, fixed = TRUE))
> # Fix duplicated final column name
> if (!(“HMMI_index_post” %in% names(df)) && (“HMMI_index_pre.1” %in% names(df))) {
+     names(df)[names(df) == “HMMI_index_pre.1”] <- “HMMI_index_post”
+ }
> for (col in c(“HMMI_index_pre”, “HMMI_index_post”)) {
+     df[[col]] <- to_num(df[[col]])
+ }
> df$condition <- tolower(trimws(df$condition))
> df$delta_hmmi <- df$HMMI_index_pre – df$HMMI_index_post
> table1 <- df %>%
+     group_by(condition) %>%
+     summarise(
+         mean_pre  = mean(HMMI_index_pre, na.rm = TRUE),
+         mean_post = mean(HMMI_index_post, na.rm = TRUE),
+         mean_delta = mean(delta_hmmi, na.rm = TRUE),
+         .groups = “drop”
+     )
> table1
# A tibble: 3 × 4
  condition mean_pre mean_post mean_delta
  <chr>        <dbl>     <dbl>      <dbl>
1 adaptive     0.532     0.731    -0.199 
2 control      0.547     0.894    -0.347 
3 generic      0.567     0.644    -0.0773
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> # 1. Зчитування файлу
> df <- read.csv(“/Users/vasylzalizko/Book2026.csv”,
+                sep = “;”,
+                stringsAsFactors = FALSE,
+                check.names = TRUE)
> # 2. Перетворення десяткових ком на числа
> to_num <- function(x) as.numeric(gsub(“,”, “.”, x, fixed = TRUE))
> # 3. Якщо post-колонка ще читається як дубльований заголовок, виправляємо
> if (!(“HMMI_index_post” %in% names(df)) && (“HMMI_index_pre.1” %in% names(df))) {
+     names(df)[names(df) == “HMMI_index_pre.1”] <- “HMMI_index_post”
+ }
> df$HMMI_index_pre  <- to_num(df$HMMI_index_pre)
> df$HMMI_index_post <- to_num(df$HMMI_index_post)
> df$condition <- tolower(trimws(df$condition))
> # 4. Підготовка довгого формату
> fig1_df <- df %>%
+     select(condition, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(cols = c(HMMI_index_pre, HMMI_index_post),
+                  names_to = “phase”, values_to = “HMMI”)
> fig1_df$phase <- recode(fig1_df$phase,
+                         HMMI_index_pre = “Pretest”,
+                         HMMI_index_post = “Posttest”)
> fig1_df$condition <- factor(fig1_df$condition,
+                             levels = c(“control”, “generic”, “adaptive”),
+                             labels = c(“Control”, “Generic support”, “Adaptive digital twin”))
> # 5. Побудова графіка
> p1 <- ggplot(fig1_df, aes(x = HMMI, fill = phase, color = phase)) +
+     geom_density(alpha = 0.25, linewidth = 1.15, adjust = 1.1) +
+     facet_wrap(~ condition, nrow = 1) +
+     scale_fill_manual(values = c(“Pretest” = “#3B82C4”, “Posttest” = “#D95F5F”)) +
+     scale_color_manual(values = c(“Pretest” = “#3B82C4”, “Posttest” = “#D95F5F”)) +
+     labs(
+         title = “Distributional shift of HMMI from pretest to posttest”,
+         subtitle = “Learner vulnerability distributions across instructional conditions”,
+         x = “HMMI”,
+         y = “Density”
+     ) +
+     theme_classic(base_size = 14) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         strip.text = element_text(face = “bold”),
+         legend.position = “top”
+     )
> # 6. Збереження
> ggsave(“figure1_density_pre_post.png”, p1, width = 10.8, height = 5.2, dpi = 300)
> # 7. Показати графік
> p1
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> # 1. Зчитування файлу
> df <- read.csv(“/Users/vasylzalizko/Book2026.csv”,
+                sep = “;”,
+                stringsAsFactors = FALSE,
+                check.names = TRUE)
> # 2. Перетворення десяткових ком на числа
> to_num <- function(x) as.numeric(gsub(“,”, “.”, x, fixed = TRUE))
> # 3. Якщо post-колонка ще читається як дубльований заголовок, виправляємо
> if (!(“HMMI_index_post” %in% names(df)) && (“HMMI_index_pre.1” %in% names(df))) {
+     names(df)[names(df) == “HMMI_index_pre.1”] <- “HMMI_index_post”
+ }
> df$HMMI_index_pre  <- to_num(df$HMMI_index_pre)
> df$HMMI_index_post <- to_num(df$HMMI_index_post)
> df$condition <- tolower(trimws(df$condition))
> # 4. Підготовка довгого формату
> fig1_df <- df %>%
+     select(condition, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(cols = c(HMMI_index_pre, HMMI_index_post),
+                  names_to = “phase”, values_to = “HMMI”)
> fig1_df$phase <- recode(fig1_df$phase,
+                         HMMI_index_pre = “Pretest”,
+                         HMMI_index_post = “Posttest”)
> fig1_df$condition <- factor(fig1_df$condition,
+                             levels = c(“control”, “generic”, “adaptive”),
+                             labels = c(“Control”, “Generic support”, “Adaptive digital twin”))
> # 5. Побудова графіка
> p1 <- ggplot(fig1_df, aes(x = HMMI, fill = phase, color = phase)) +
+     geom_density(alpha = 0.25, linewidth = 1.15, adjust = 1.1) +
+     facet_wrap(~ condition, nrow = 1) +
+     scale_fill_manual(values = c(“Pretest” = “#3B82C4”, “Posttest” = “#D95F5F”)) +
+     scale_color_manual(values = c(“Pretest” = “#3B82C4”, “Posttest” = “#D95F5F”)) +
+     labs(
+         title = “Distributional shift of HMMI from pretest to posttest”,
+         subtitle = “Learner vulnerability distributions across instructional conditions”,
+         x = “HMMI”,
+         y = “Density”
+     ) +
+     theme_classic(base_size = 14) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         strip.text = element_text(face = “bold”),
+         legend.position = “top”
+     )
> # 6. Збереження
> ggsave(“figure1_density_pre_post.png”, p1, width = 10.8, height = 5.2, dpi = 300)
> # 7. Показати графік
> p1
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> # 1. Зчитування файлу
> df <- read.csv(“/Users/vasylzalizko/Book2026.csv”,
+                sep = “;”,
+                stringsAsFactors = FALSE,
+                check.names = TRUE)
> # 2. Перетворення десяткових ком на числа
> to_num <- function(x) as.numeric(gsub(“,”, “.”, x, fixed = TRUE))
> # 3. Якщо post-колонка ще читається як дубльований заголовок, виправляємо
> if (!(“HMMI_index_post” %in% names(df)) && (“HMMI_index_pre.1” %in% names(df))) {
+     names(df)[names(df) == “HMMI_index_pre.1”] <- “HMMI_index_post”
+ }
> df$HMMI_index_pre  <- to_num(df$HMMI_index_pre)
> df$HMMI_index_post <- to_num(df$HMMI_index_post)
> df$condition <- tolower(trimws(df$condition))
> # 4. Довгий формат
> fig1_df <- df %>%
+     select(condition, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(cols = c(HMMI_index_pre, HMMI_index_post),
+                  names_to = “phase”, values_to = “HMMI”)
> fig1_df$phase <- recode(fig1_df$phase,
+                         HMMI_index_pre = “Pretest”,
+                         HMMI_index_post = “Posttest”)
> fig1_df$condition <- factor(fig1_df$condition,
+                             levels = c(“control”, “generic”, “adaptive”),
+                             labels = c(“Control”, “Generic support”, “Adaptive digital twin”))
> # 5. Штрихові density lines
> p1 <- ggplot(fig1_df, aes(x = HMMI, color = phase, linetype = phase)) +
+     geom_density(linewidth = 1.2, adjust = 1.1) +
+     facet_wrap(~ condition, nrow = 1) +
+     scale_color_manual(values = c(“Pretest” = “#3B82C4”, “Posttest” = “#D95F5F”)) +
+     scale_linetype_manual(values = c(“Pretest” = “dashed”, “Posttest” = “solid”)) +
+     labs(
+         title = “Distributional shift of HMMI from pretest to posttest”,
+         subtitle = “Learner vulnerability distributions across instructional conditions”,
+         x = “HMMI”,
+         y = “Density”
+     ) +
+     theme_classic(base_size = 14) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         strip.text = element_text(face = “bold”),
+         legend.position = “top”
+     )
> # 6. Збереження
> ggsave(“figure1_density_pre_post_dashed.png”, p1, width = 10.8, height = 5.2, dpi = 300)
> # 7. Показати графік
> p1
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> df <- read.csv(“/Users/vasylzalizko/Book2026.csv”,
+                sep = “;”,
+                stringsAsFactors = FALSE,
+                check.names = TRUE)
> to_num <- function(x) as.numeric(gsub(“,”, “.”, x, fixed = TRUE))
> if (!(“HMMI_index_post” %in% names(df)) && (“HMMI_index_pre.1” %in% names(df))) {
+     names(df)[names(df) == “HMMI_index_pre.1”] <- “HMMI_index_post”
+ }
> df$HMMI_index_pre  <- to_num(df$HMMI_index_pre)
> df$HMMI_index_post <- to_num(df$HMMI_index_post)
> df$condition <- tolower(trimws(df$condition))
> plot_df <- df %>%
+     mutate(id = row_number()) %>%
+     select(id, condition, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(cols = c(HMMI_index_pre, HMMI_index_post),
+                  names_to = “timepoint”, values_to = “score”)
> plot_df$timepoint <- factor(plot_df$timepoint,
+                             levels = c(“HMMI_index_pre”, “HMMI_index_post”),
+                             labels = c(“Pre”, “Post”))
> plot_df$condition <- factor(plot_df$condition,
+                             levels = c(“control”, “generic”, “adaptive”),
+                             labels = c(“Control”, “Generic support”, “Adaptive digital twin”))
> mean_df <- plot_df %>%
+     group_by(condition, timepoint) %>%
+     summarise(mean_score = mean(score, na.rm = TRUE), .groups = “drop”)
> p_spaghetti_mean <- ggplot(plot_df, aes(x = timepoint, y = score, group = id)) +
+     geom_line(alpha = 0.18, linewidth = 0.6, color = “grey50”) +
+     geom_point(alpha = 0.25, size = 1.3, color = “grey35”) +
+     geom_line(data = mean_df, aes(x = timepoint, y = mean_score, group = 1),
+               color = “#D62828”, linewidth = 1.6) +
+     geom_point(data = mean_df, aes(x = timepoint, y = mean_score),
+                color = “#D62828”, size = 3) +
+     facet_wrap(~ condition, nrow = 1) +
+     labs(
+         title = “Individual learning progress: pre vs post”,
+         subtitle = “Grey lines represent learners; red lines indicate group means”,
+         x = “Timepoint”,
+         y = “HMMI”
+     ) +
+     theme_minimal(base_size = 14) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         strip.text = element_text(face = “bold”),
+         legend.position = “none”
+     )
> ggsave(“figure_pre_post_individual_plus_mean.png”, p_spaghetti_mean,
+        width = 10.8, height = 5.8, dpi = 300)
Error in `geom_point()`:
! Problem while computing aesthetics.
ℹ Error occurred in the 4th layer.
Caused by error:
! object ‘id’ not found
Backtrace:
  1. ggplot2::ggsave(…)
  2. base::lapply(plot, grid.draw)
  4. ggplot2 (local) `grid.draw.ggplot2::ggplot`(X[[i]], …)
  6. ggplot2 (local) `print.ggplot2::ggplot`(x)
  8. ggplot2 (local) `ggplot_build.ggplot2::ggplot`(x)
     …
 17. l$compute_aesthetics(d, plot)
 18. ggplot2 (local) compute_aesthetics(…, self = self)
 19. ggplot2:::eval_aesthetics(aesthetics, data)
 20. base::lapply(aesthetics, eval_tidy, data = data, env = env)
 21. rlang (local) FUN(X[[i]], …)
 
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> df <- read.csv(“/Users/vasylzalizko/Book2026.csv”,
+                sep = “;”,
+                stringsAsFactors = FALSE,
+                check.names = TRUE)
> to_num <- function(x) as.numeric(gsub(“,”, “.”, x, fixed = TRUE))
> if (!(“HMMI_index_post” %in% names(df)) && (“HMMI_index_pre.1” %in% names(df))) {
+     names(df)[names(df) == “HMMI_index_pre.1”] <- “HMMI_index_post”
+ }
> df$HMMI_index_pre  <- to_num(df$HMMI_index_pre)
> df$HMMI_index_post <- to_num(df$HMMI_index_post)
> df$condition <- tolower(trimws(df$condition))
> plot_df <- df %>%
+     mutate(id = row_number()) %>%
+     select(id, condition, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(cols = c(HMMI_index_pre, HMMI_index_post),
+                  names_to = “timepoint”, values_to = “score”)
> plot_df$timepoint <- factor(plot_df$timepoint,
+                             levels = c(“HMMI_index_pre”, “HMMI_index_post”),
+                             labels = c(“Pre”, “Post”))
> plot_df$condition <- factor(plot_df$condition,
+                             levels = c(“control”, “generic”, “adaptive”),
+                             labels = c(“Control”, “Generic support”, “Adaptive digital twin”))
> p_spaghetti_col <- ggplot(plot_df, aes(x = timepoint, y = score, group = id, color = condition)) +
+     geom_line(alpha = 0.25, linewidth = 0.7) +
+     geom_point(size = 1.7, alpha = 0.45) +
+     facet_wrap(~ condition, nrow = 1) +
+     scale_color_manual(values = c(
+         “Control” = “#2E7D32”,
+         “Generic support” = “#1565C0”,
+         “Adaptive digital twin” = “#B23A48”
+     )) +
+     labs(
+         title = “Individual learning progress: pre vs post”,
+         x = “Timepoint”,
+         y = “HMMI”
+     ) +
+     theme_minimal(base_size = 14) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         strip.text = element_text(face = “bold”),
+         legend.position = “none”
+     )
> ggsave(“figure_pre_post_individual_progress_colored.png”, p_spaghetti_col,
+        width = 10.5, height = 5.8, dpi = 300)
> p_spaghetti_col
> library(ggplot2)
> library(dplyr)
> # 1. Завантаження даних
> df <- read.csv(file.choose(), sep = “;”, dec = “,”)
Error in file.choose() : file choice cancelled
 
> library(ggplot2)
> library(dplyr)
> # 1. Завантаження даних
> df <- read.csv(file.choose(), sep = “;”, dec = “,”)
Error in file.choose() : file choice cancelled
 
> library(ggplot2)
> library(dplyr)
> # 1. Завантаження даних
> df <- read.csv(file.choose(), sep = “;”, dec = “,”)
> # 2. Побудова графіка
> p_scatter <- ggplot(df, aes(x = T_index_pre, y = V_index_pre, color = condition)) +
+     # geom_point з shape = 15 створює заповнені квадрати
+     geom_point(aes(shape = condition), size = 3, alpha = 0.6) + 
+     # Додаємо лінії тренду (regression lines)
+     geom_smooth(method = “lm”, se = FALSE, size = 1.2) +
+     # Використовуємо форму 15 (заповнений квадрат) для всіх груп
+     scale_shape_manual(values = c(15, 15, 15)) +
+     # ОНОВЛЕНА КОЛІРНА ПАЛІТРА (Виразні кольори для статті)
+     # Контрольна (модель) – Зелений, Generic (маніпуляції) – Червоний, Adaptive – Помаранчевий
+     scale_color_manual(values = c(“#27ae60”, “#e74c3c”, “#f39c12”)) +
+     theme_minimal() +
+     labs(title = “Figure 1: Cognitive Dissonance in Modality Integration”,
+          subtitle = “Scatter plot showing distinct integration patterns (Squares)”,
+          x = “Text Understanding Anchor (T_index)”, 
+          y = “Visual Information Interpretation (V_index)”,
+          color = “Educational Approach”,
+          shape = “Educational Approach”) +
+     theme(legend.position = “bottom”,
+           text = element_text(size = 12),
+           plot.title = element_text(size = 14, face = “bold”))
> # 3. Вивід та збереження для LaTeX
> print(p_scatter)
`geom_smooth()` using formula = ‘y ~ x’
> ggsave(“Fig1_Squares_Scatter.png”, p_scatter, width = 8, height = 6, dpi = 300)
`geom_smooth()` using formula = ‘y ~ x’
> # 1. ВСТАНОВЛЕННЯ ТА ЗАВАНТАЖЕННЯ БІБЛІОТЕК
> if (!require(“tidyverse”)) install.packages(“tidyverse”)
> if (!require(“ggdist”)) install.packages(“ggdist”)
Loading required package: ggdist
also installing the dependency ‘distributional’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/distributional_0.7.0.tgz’
trying URL ‘https://cran.rstudio.com/bin/macosx/big-sur-arm64/contrib/4.5/ggdist_3.3.3.tgz’
 
The downloaded binary packages are in
/var/folders/n6/295fw91d3jz7qtpgw5zm41_r0000gn/T//RtmpxADw6P/downloaded_packages
Warning message:
In library(package, lib.loc = lib.loc, character.only = TRUE, logical.return = TRUE,  :
  there is no package called ‘ggdist’
> library(tidyverse)
> library(ggdist)
> # 2. ЗАВАНТАЖЕННЯ ДАНИХ
> # Виберіть ваш файл Book2026.csv
> df <- read.csv(file.choose(), sep = “;”, dec = “,”)
Error in file.choose() : file choice cancelled
 
> library(ggplot2)
> # 1. Завантаження даних
> df <- read.csv(file.choose(), sep = “;”, dec = “,”)
Error in file.choose() : file choice cancelled
 
> library(ggplot2)
> # 1. Завантаження без діалогових вікон
> # Файл має називатися саме так і лежати в робочій директорії
> df <- read.csv(“Book2026.csv”, sep = “;”, dec = “,”)
> # 2. Малюємо “Когнітивну ілюзію” з квадратами
> p_squares <- ggplot(df, aes(x = T_index_pre, y = V_index_pre, color = condition)) +
+     # geom_point з shape = 15 робить точки квадратами
+     geom_point(shape = 15, size = 3, alpha = 0.6) + 
+     # Прямі лінії тренду (лінійна модель)
+     geom_smooth(method = “lm”, se = FALSE, size = 1.2) +
+     # Ваша палітра: Control – зелений, Generic – червоний, Adaptive – помаранчевий
+     scale_color_manual(values = c(
+         “control” = “#27ae60”, 
+         “generic” = “#e74c3c”, 
+         “adaptive” = “#f39c12”
+     )) +
+     # Лаконічне оформлення для статті
+     theme_bw() + 
+     labs(
+         title = “Multimodal Cognitive Illusion Patterns”,
+         subtitle = “Visualizing the gap between Text (Anchor) and Visual Perception”,
+         x = “Textual Baseline Index”,
+         y = “Visual Interpretation Index”,
+         color = “Model Condition”
+     ) +
+     theme(
+         legend.position = “bottom”,
+         panel.grid.minor = element_blank()
+     )
> # 3. Вивід на екран та збереження
> print(p_squares)
`geom_smooth()` using formula = ‘y ~ x’
> ggsave(“Cognitive_Squares_Plot.png”, p_squares, width = 8, height = 6, dpi = 300)
`geom_smooth()` using formula = ‘y ~ x’
> library(ggplot2)
> # 1. Завантаження без діалогових вікон
> # Файл має називатися саме так і лежати в робочій директорії
> df <- read.csv(“Book2026.csv”, sep = “;”, dec = “,”)
> # 2. Малюємо “Когнітивну ілюзію” з квадратами
> p_squares <- ggplot(df, aes(x = T_index_pre, y = V_index_pre, color = condition)) +
+     # geom_point з shape = 15 робить точки квадратами
+     geom_point(aes(shape = condition), size = 3, alpha = 0.6) + 
+     # Використовуємо квадрати для всіх груп
+     scale_shape_manual(values = c(15, 15, 15)) +
+     # Прямі лінії тренду (лінійна модель)
+     geom_smooth(method = “lm”, se = FALSE, size = 1.2) +
+     # Точна колірна палітра: Control – зелений, Generic – червоний, Adaptive – помаранчевий
+     scale_color_manual(values = c(
+         “control” = “#27ae60”, 
+         “generic” = “#e74c3c”, 
+         “adaptive” = “#f39c12”
+     )) +
+     # Лаконічне оформлення для статті
+     theme_bw() + 
+     labs(
+         title = “Multimodal Cognitive Illusion Patterns”,
+         subtitle = “Visualizing the gap between Text (Anchor) and Visual Perception”,
+         x = “Textual Baseline Index”,
+         y = “Visual Interpretation Index”,
+         color = “Model Condition”,
+         shape = “Model Condition”
+     ) +
+     theme(
+         legend.position = “bottom”,
+         panel.grid.minor = element_blank()
+     )
> # 3. Вивід на екран та збереження
> print(p_squares)
`geom_smooth()` using formula = ‘y ~ x’
> ggsave(“Cognitive_Squares_Plot.png”, p_squares, width = 8, height = 6, dpi = 300)
`geom_smooth()` using formula = ‘y ~ x’
> # Встановіть бібліотеку, якщо вона не встановлена: install.packages(“ggplot2”)
> library(ggplot2)
> # Функція для генерації точок кола (для оточуючих елементів)
> get_circle <- function(center_x, center_y, n_points = 8, distance, size) {
+     angles <- seq(0, 2*pi, length.out = n_points + 1)[1:n_points]
+     data.frame(
+         x = center_x + cos(angles) * distance,
+         y = center_y + sin(angles) * distance,
+         size = size
+     )
+ }
> # Параметри для лівої частини (великі оточуючі кола)
> left_surround <- get_circle(center_x = 1, center_y = 1, n_points = 6, distance = 0.6, size = 0.45)
> # Параметри для правої частини (малі оточуючі кола)
> right_surround <- get_circle(center_x = 3, center_y = 1, n_points = 8, distance = 0.3, size = 0.1)
> # Малювання
> ggplot() +
+     # Малюємо оточуючі сірі кола
+     geom_point(data = left_surround, aes(x, y), size = 50, color = “lightgrey”) +
+     geom_point(data = right_surround, aes(x, y), size = 12, color = “lightgrey”) +
+     # Малюємо центральні сині квадрати (однакового розміру)
+     geom_rect(aes(xmin = 0.9, xmax = 1.1, ymin = 0.9, ymax = 1.1), fill = “blue”, color = “black”) +
+     geom_rect(aes(xmin = 2.9, xmax = 3.1, ymin = 0.9, ymax = 1.1), fill = “blue”, color = “black”) +
+     # Налаштування вигляду
+     coord_fixed() +
+     theme_void() +
+     labs(title = “Який синій квадрат здається більшим?”,
+          subtitle = “Спойлер: вони ідентичні”) +
+     theme(plot.title = element_text(hjust = 0.5, size = 20),
+           plot.subtitle = element_text(hjust = 0.5, size = 14))
> library(ggplot2)
> library(ggforce) # Пакет для малювання ідеальних кіл
> # Створюємо дані для оточуючих кіл
> # Зліва: 6 великих кіл
> left_circles <- data.frame(
+     x0 = 1 + 0.7 * cos(seq(0, 2*pi, length.out = 7)[1:6]),
+     y0 = 1 + 0.7 * sin(seq(0, 2*pi, length.out = 7)[1:6]),
+     r = 0.45
+ )
> # Справа: 8 маленьких кіл
> right_circles <- data.frame(
+     x0 = 4 + 0.4 * cos(seq(0, 2*pi, length.out = 9)[1:8]),
+     y0 = 1 + 0.4 * sin(seq(0, 2*pi, length.out = 9)[1:8]),
+     r = 0.12
+ )
> ggplot() +
+     # Малюємо великі кола (ліва частина)
+     geom_circle(data = left_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     # Малюємо малі кола (права частина)
+     geom_circle(data = right_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     
+     # Малюємо сині квадрати (xmin/xmax та ymin/ymax однакові для обох!)
+     # Лівий квадрат (центр 1,1)
+     geom_rect(aes(xmin = 0.85, xmax = 1.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     # Правий квадрат (центр 4,1)
+     geom_rect(aes(xmin = 3.85, xmax = 4.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     
+     # Налаштування візуалізації
+     coord_fixed() +
+     theme_void() +
+     labs(title = “Ілюзія Еббінгауза: Сині Квадрати”,
+          subtitle = “Обидва сині квадрати мають однаковий розмір”) +
+     theme(plot.title = element_text(hjust = 0.5, face = “bold”, size = 18),
+           plot.subtitle = element_text(hjust = 0.5))
> library(ggplot2)
> library(ggforce) # Пакет для малювання ідеальних кіл
> # Створюємо дані для оточуючих кіл
> # Зліва: 6 великих кіл
> left_circles <- data.frame(
+     x0 = 1 + 0.7 * cos(seq(0, 2*pi, length.out = 7)[1:6]),
+     y0 = 1 + 0.7 * sin(seq(0, 2*pi, length.out = 7)[1:6]),
+     r = 0.45
+ )
> # Справа: 8 маленьких кіл
> right_circles <- data.frame(
+     x0 = 4 + 0.4 * cos(seq(0, 2*pi, length.out = 9)[1:8]),
+     y0 = 1 + 0.4 * sin(seq(0, 2*pi, length.out = 9)[1:8]),
+     r = 0.12
+ )
> ggplot() +
+     # Малюємо великі кола (ліва частина)
+     geom_circle(data = left_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     # Малюємо малі кола (права частина)
+     geom_circle(data = right_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     
+     # Малюємо сині квадрати (xmin/xmax та ymin/ymax однакові для обох!)
+     # Лівий квадрат (центр 1,1)
+     geom_rect(aes(xmin = 0.85, xmax = 1.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     # Правий квадрат (центр 4,1)
+     geom_rect(aes(xmin = 3.85, xmax = 4.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     
+     # Налаштування візуалізації
+     coord_fixed() +
+     theme_void() +
+     labs(title = “How much bigger is the square on the right than the one on the left?”,
+          subtitle = “) +
+     theme(plot.title = element_text(hjust = 0.5, face = “bold”, size = 18),
Error: unexpected symbol in:
”         subtitle = “) +
    theme(plot.title = element_text(hjust = 0.5, face = “bold”
 
> library(ggplot2)
> library(ggforce) # Пакет для малювання ідеальних кіл
> # Створюємо дані для оточуючих кіл
> # Зліва: 6 великих кіл
> left_circles <- data.frame(
+     x0 = 1 + 0.7 * cos(seq(0, 2*pi, length.out = 7)[1:6]),
+     y0 = 1 + 0.7 * sin(seq(0, 2*pi, length.out = 7)[1:6]),
+     r = 0.45
+ )
> # Справа: 8 маленьких кіл
> right_circles <- data.frame(
+     x0 = 4 + 0.4 * cos(seq(0, 2*pi, length.out = 9)[1:8]),
+     y0 = 1 + 0.4 * sin(seq(0, 2*pi, length.out = 9)[1:8]),
+     r = 0.12
+ )
> ggplot() +
+     # Малюємо великі кола (ліва частина)
+     geom_circle(data = left_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     # Малюємо малі кола (права частина)
+     geom_circle(data = right_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     
+     # Малюємо сині квадрати (xmin/xmax та ymin/ymax однакові для обох!)
+     # Лівий квадрат (центр 1,1)
+     geom_rect(aes(xmin = 0.85, xmax = 1.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     # Правий квадрат (центр 4,1)
+     geom_rect(aes(xmin = 3.85, xmax = 4.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     
+     # Налаштування візуалізації
+     coord_fixed() +
+     theme_void() +
+     labs(title = “How much bigger is the square on the right than the one on the left?”,
+          subtitle = “) +
+     theme(plot.title = element_text(hjust = 0.5, face = “bold”, size = 18),
Error: unexpected symbol in:
”         subtitle = “) +
    theme(plot.title = element_text(hjust = 0.5, face = “bold”
 
> library(ggplot2)
> library(ggforce) # Пакет для малювання ідеальних кіл
> # Створюємо дані для оточуючих кіл
> # Зліва: 6 великих кіл
> left_circles <- data.frame(
+     x0 = 1 + 0.7 * cos(seq(0, 2*pi, length.out = 7)[1:6]),
+     y0 = 1 + 0.7 * sin(seq(0, 2*pi, length.out = 7)[1:6]),
+     r = 0.45
+ )
> # Справа: 8 маленьких кіл
> right_circles <- data.frame(
+     x0 = 4 + 0.4 * cos(seq(0, 2*pi, length.out = 9)[1:8]),
+     y0 = 1 + 0.4 * sin(seq(0, 2*pi, length.out = 9)[1:8]),
+     r = 0.12
+ )
> ggplot() +
+     # Малюємо великі кола (ліва частина)
+     geom_circle(data = left_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     # Малюємо малі кола (права частина)
+     geom_circle(data = right_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     
+     # Малюємо сині квадрати (xmin/xmax та ymin/ymax однакові для обох!)
+     # Лівий квадрат (центр 1,1)
+     geom_rect(aes(xmin = 0.85, xmax = 1.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     # Правий квадрат (центр 4,1)
+     geom_rect(aes(xmin = 3.85, xmax = 4.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     
+     # Налаштування візуалізації
+     coord_fixed() +
+     theme_void() +
+     labs(title = “How much bigger is the square on the right than the one on the left?”,
+          subtitle = “) +
+     theme(plot.title = element_text(hjust = 0.5, face = “bold”, size = 18),
Error: unexpected symbol in:
”         subtitle = “) +
    theme(plot.title = element_text(hjust = 0.5, face = “bold”
 
> How much bigger is the square on the right than the one on the left?
Error: unexpected symbol in “How much”
 
> library(ggplot2)
> library(ggforce) # Пакет для малювання ідеальних кіл
> # Створюємо дані для оточуючих кіл
> # Зліва: 6 великих кіл
> left_circles <- data.frame(
+     x0 = 1 + 0.7 * cos(seq(0, 2*pi, length.out = 7)[1:6]),
+     y0 = 1 + 0.7 * sin(seq(0, 2*pi, length.out = 7)[1:6]),
+     r = 0.45
+ )
> # Справа: 8 маленьких кіл
> right_circles <- data.frame(
+     x0 = 4 + 0.4 * cos(seq(0, 2*pi, length.out = 9)[1:8]),
+     y0 = 1 + 0.4 * sin(seq(0, 2*pi, length.out = 9)[1:8]),
+     r = 0.12
+ )
> ggplot() +
+     # Малюємо великі кола (ліва частина)
+     geom_circle(data = left_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     # Малюємо малі кола (права частина)
+     geom_circle(data = right_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     
+     # Малюємо сині квадрати (xmin/xmax та ymin/ymax однакові для обох!)
+     # Лівий квадрат (центр 1,1)
+     geom_rect(aes(xmin = 0.85, xmax = 1.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     # Правий квадрат (центр 4,1)
+     geom_rect(aes(xmin = 3.85, xmax = 4.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     
+     # Налаштування візуалізації
+     coord_fixed() +
+     theme_void() +
+     labs(title = “Ілюзія Еббінгауза: Сині Квадрати”,
+          subtitle = “Обидва сині квадрати мають однаковий розмір”) +
+     theme(plot.title = element_text(hjust = 0.5, face = “bold”, size = 18),
+           plot.subtitle = element_text(hjust = 0.5))
> library(ggplot2)
> library(ggforce) # Пакет для малювання ідеальних кіл
> # Створюємо дані для оточуючих кіл
> # Зліва: 6 великих кіл
> left_circles <- data.frame(
+     x0 = 1 + 0.7 * cos(seq(0, 2*pi, length.out = 7)[1:6]),
+     y0 = 1 + 0.7 * sin(seq(0, 2*pi, length.out = 7)[1:6]),
+     r = 0.45
+ )
> # Справа: 8 маленьких кіл
> right_circles <- data.frame(
+     x0 = 4 + 0.4 * cos(seq(0, 2*pi, length.out = 9)[1:8]),
+     y0 = 1 + 0.4 * sin(seq(0, 2*pi, length.out = 9)[1:8]),
+     r = 0.12
+ )
> ggplot() +
+     # Малюємо великі кола (ліва частина)
+     geom_circle(data = left_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     # Малюємо малі кола (права частина)
+     geom_circle(data = right_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     
+     # Малюємо сині квадрати (xmin/xmax та ymin/ymax однакові для обох!)
+     # Лівий квадрат (центр 1,1)
+     geom_rect(aes(xmin = 0.85, xmax = 1.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     # Правий квадрат (центр 4,1)
+     geom_rect(aes(xmin = 3.85, xmax = 4.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     
+     # Налаштування візуалізації
+     coord_fixed() +
+     theme_void() +
+     labs(title = “How much bigger is the square on the right than the one on the left?”,
+          subtitle = “Please explain your answer”) +
+     theme(plot.title = element_text(hjust = 0.5, face = “bold”, size = 18),
+           plot.subtitle = element_text(hjust = 0.5))
> library(ggplot2)
> library(ggforce) # Пакет для малювання ідеальних кіл
> # Створюємо дані для оточуючих кіл
> # Зліва: 6 великих кіл
> left_circles <- data.frame(
+     x0 = 1 + 0.7 * cos(seq(0, 2*pi, length.out = 7)[1:6]),
+     y0 = 1 + 0.7 * sin(seq(0, 2*pi, length.out = 7)[1:6]),
+     r = 0.45
+ )
> # Справа: 8 маленьких кіл
> right_circles <- data.frame(
+     x0 = 4 + 0.4 * cos(seq(0, 2*pi, length.out = 9)[1:8]),
+     y0 = 1 + 0.4 * sin(seq(0, 2*pi, length.out = 9)[1:8]),
+     r = 0.12
+ )
> ggplot() +
+     # Малюємо великі кола (ліва частина)
+     geom_circle(data = left_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     # Малюємо малі кола (права частина)
+     geom_circle(data = right_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     
+     # Малюємо сині квадрати (xmin/xmax та ymin/ymax однакові для обох!)
+     # Лівий квадрат (центр 1,1)
+     geom_rect(aes(xmin = 0.85, xmax = 1.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     # Правий квадрат (центр 4,1)
+     geom_rect(aes(xmin = 3.85, xmax = 4.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     
+     # Налаштування візуалізації
+     coord_fixed() +
+     theme_void() +
+     labs(title = “How much bigger is the square on the right than the one on the left?”,
+          subtitle = “Please explain your answer”) +
+     theme(plot.title = element_text(hjust = 0.5, face = “bold”, size = 18),
+           plot.subtitle = element_text(hjust = 0.5))
> library(ggplot2)
> library(ggforce) # Пакет для малювання ідеальних кіл
> # Створюємо дані для оточуючих кіл
> # Зліва: 6 великих кіл
> left_circles <- data.frame(
+     x0 = 1 + 0.7 * cos(seq(0, 2*pi, length.out = 7)[1:6]),
+     y0 = 1 + 0.7 * sin(seq(0, 2*pi, length.out = 7)[1:6]),
+     r = 0.45
+ )
> # Справа: 8 маленьких кіл
> right_circles <- data.frame(
+     x0 = 4 + 0.4 * cos(seq(0, 2*pi, length.out = 9)[1:8]),
+     y0 = 1 + 0.4 * sin(seq(0, 2*pi, length.out = 9)[1:8]),
+     r = 0.12
+ )
> ggplot() +
+     # Малюємо великі кола (ліва частина)
+     geom_circle(data = left_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     # Малюємо малі кола (права частина)
+     geom_circle(data = right_circles, aes(x0=x0, y0=y0, r=r), 
+                 fill = “lightgrey”, color = “grey40”) +
+     
+     # Малюємо сині квадрати (xmin/xmax та ymin/ymax однакові для обох!)
+     # Лівий квадрат (центр 1,1)
+     geom_rect(aes(xmin = 0.85, xmax = 1.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     # Правий квадрат (центр 4,1)
+     geom_rect(aes(xmin = 3.85, xmax = 4.15, ymin = 0.85, ymax = 1.15), 
+               fill = “blue”, color = “black”, linewidth = 0.8) +
+     
+     # Налаштування візуалізації
+     coord_fixed() +
+     theme_void() +
+     labs(title = “How much bigger is the square on 
+          the right than the one on the left?”,
+          subtitle = “Please explain your answer”) +
+     theme(plot.title = element_text(hjust = 0.5, face = “bold”, size = 18),
+           plot.subtitle = element_text(hjust = 0.5))
> # Якщо пакети не встановлені, розкоментуйте та виконайте:
> # install.packages(c(“ggplot2”, “ggforce”))
> library(ggplot2)
> library(ggforce) # Пакет для малювання правильних багатокутників (трикутників)
> # — Налаштування —
> # Колір фону
> bg_color <- “white”
> # — Функція для створення оточення з трикутників —
> # Вона генерує координати для центрів трикутників, розташованих по колу.
> get_triangles <- function(center_x, center_y, n_triangles, distance, size, angle_offset = 0) {
+     # Кути розташування центрів трикутників навколо центральної фігури
+     pos_angles <- seq(0, 2*pi, length.out = n_triangles + 1)[1:n_triangles]
+     
+     data.frame(
+         x = center_x + cos(pos_angles) * distance,
+         y = center_y + sin(pos_angles) * distance,
+         r = size,
+         # Додаємо обертання для кожного трикутника, щоб вони “дивилися” на центр
+         angle = pos_angles + angle_offset 
+     )
+ }
> # — Параметри —
> # Розмір центральних квадратів (однаковий!)
> sq_size <- 0.15
> # ЛІВА ЧАСТИНА (великі фігури)
> left_x <- 1
> num_left <- 6
> dist_left <- 0.7  # Відстань від центру
> size_left <- 0.4  # Розмір трикутників
> # ПРАВА ЧАСТИНА (малі фігури)
> right_x <- 4
> num_right <- 8
> dist_right <- 0.4 # Відстань від центру
> size_right <- 0.1 # Розмір трикутників
> # — Генерація даних —
> # n=3 для geom_regon означає трикутник
> left_data <- get_triangles(left_x, 1, num_left, dist_left, size_left, angle_offset = pi/num_left)
> right_data <- get_triangles(right_x, 1, num_right, dist_right, size_right, angle_offset = 0)
> # — Візуалізація —
> ggplot() +
+     
+     # 1. Малюємо ЛІВЕ оточення (великі сірі трикутники)
+     # angle = pi/2 повертає трикутник вершиною вгору, sides=3 – трикутник
+     geom_regon(data = left_data, 
+                aes(x0 = x, y0 = y, r = r, angle = pi/2, sides = 3), 
+                fill = “lightgrey”, color = “grey40”, linewidth = 0.5) +
+     
+     # 2. Малюємо ПРАВЕ оточення (малі сірі трикутники)
+     geom_regon(data = right_data, 
+                aes(x0 = x, y0 = y, r = r, angle = pi/2, sides = 3), 
+                fill = “lightgrey”, color = “grey40”, linewidth = 0.5) +
+     
+     # 3. Малюємо ЦЕНТРАЛЬНІ СИНІ КВАДРАТИ (geom_rect використовує координати кутів)
+     # Лівий квадрат (центр: left_x, 1)
+     geom_rect(aes(xmin = left_x – sq_size, xmax = left_x + sq_size, 
+                   ymin = 1 – sq_size, ymax = 1 + sq_size), 
+               fill = “blue”, color = “black”, linewidth = 1) +
+     
+     # Правий квадрат (центр: right_x, 1)
+     geom_rect(aes(xmin = right_x – sq_size, xmax = right_x + sq_size, 
+                   ymin = 1 – sq_size, ymax = 1 + sq_size), 
+               fill = “blue”, color = “black”, linewidth = 1) +
+     
+     # — Налаштування вісі та теми —
+     coord_fixed(ratio = 1, xlim = c(-0.2, 5.2), ylim = c(0, 2)) +
+     theme_void() +
+     labs(title = “Ілюзія Еббінгауза з Трикутниками”,
+          subtitle = “Обидва сині квадрати мають однаковий розмір”) +
+     theme(plot.background = element_rect(fill = bg_color, color = NA),
+           panel.background = element_rect(fill = bg_color, color = NA),
+           plot.title = element_text(hjust = 0.5, face = “bold”, size = 20),
+           plot.subtitle = element_text(hjust = 0.5, size = 16),
+           legend.position = “none”)
> # Якщо пакети не встановлені, розкоментуйте та виконайте:
> # install.packages(c(“ggplot2”, “ggforce”))
> library(ggplot2)
> library(ggforce) # Пакет для малювання правильних багатокутників (трикутників)
> # — Налаштування —
> # Колір фону
> bg_color <- “white”
> # — Функція для створення оточення з трикутників —
> # Вона генерує координати для центрів трикутників, розташованих по колу.
> get_triangles <- function(center_x, center_y, n_triangles, distance, size, angle_offset = 0) {
+     # Кути розташування центрів трикутників навколо центральної фігури
+     pos_angles <- seq(0, 2*pi, length.out = n_triangles + 1)[1:n_triangles]
+     
+     data.frame(
+         x = center_x + cos(pos_angles) * distance,
+         y = center_y + sin(pos_angles) * distance,
+         r = size,
+         # Додаємо обертання для кожного трикутника, щоб вони “дивилися” на центр
+         angle = pos_angles + angle_offset 
+     )
+ }
> # — Параметри —
> # Розмір центральних квадратів (однаковий!)
> sq_size <- 0.15
> # ЛІВА ЧАСТИНА (великі фігури)
> left_x <- 1
> num_left <- 6
> dist_left <- 0.7  # Відстань від центру
> size_left <- 0.4  # Розмір трикутників
> # ПРАВА ЧАСТИНА (малі фігури)
> right_x <- 4
> num_right <- 8
> dist_right <- 0.4 # Відстань від центру
> size_right <- 0.1 # Розмір трикутників
> # — Генерація даних —
> # n=3 для geom_regon означає трикутник
> left_data <- get_triangles(left_x, 1, num_left, dist_left, size_left, angle_offset = pi/num_left)
> right_data <- get_triangles(right_x, 1, num_right, dist_right, size_right, angle_offset = 0)
> # — Візуалізація —
> ggplot() +
+     
+     # 1. Малюємо ЛІВЕ оточення (великі сірі трикутники)
+     # angle = pi/2 повертає трикутник вершиною вгору, sides=3 – трикутник
+     geom_regon(data = left_data, 
+                aes(x0 = x, y0 = y, r = r, angle = pi/2, sides = 3), 
+                fill = “lightgrey”, color = “grey40”, linewidth = 0.5) +
+     
+     # 2. Малюємо ПРАВЕ оточення (малі сірі трикутники)
+     geom_regon(data = right_data, 
+                aes(x0 = x, y0 = y, r = r, angle = pi/2, sides = 3), 
+                fill = “lightgrey”, color = “grey40”, linewidth = 0.5) +
+     
+     # 3. Малюємо ЦЕНТРАЛЬНІ СИНІ КВАДРАТИ (geom_rect використовує координати кутів)
+     # Лівий квадрат (центр: left_x, 1)
+     geom_rect(aes(xmin = left_x – sq_size, xmax = left_x + sq_size, 
+                   ymin = 1 – sq_size, ymax = 1 + sq_size), 
+               fill = “blue”, color = “black”, linewidth = 1) +
+     
+     # Правий квадрат (центр: right_x, 1)
+     geom_rect(aes(xmin = right_x – sq_size, xmax = right_x + sq_size, 
+                   ymin = 1 – sq_size, ymax = 1 + sq_size), 
+               fill = “blue”, color = “black”, linewidth = 1) +
+     
+     # — Налаштування вісі та теми —
+     coord_fixed(ratio = 1, xlim = c(-0.2, 5.2), ylim = c(0, 2)) +
+     theme_void() +
+     labs(title = “Compare the areas of the square on the right and the square on the left”,
+          subtitle = “Explain in writing”) +
+     theme(plot.background = element_rect(fill = bg_color, color = NA),
+           panel.background = element_rect(fill = bg_color, color = NA),
+           plot.title = element_text(hjust = 0.5, face = “bold”, size = 20),
+           plot.subtitle = element_text(hjust = 0.5, size = 16),
+           legend.position = “none”)
> # Якщо пакети не встановлені, розкоментуйте та виконайте:
> # install.packages(c(“ggplot2”, “ggforce”))
> library(ggplot2)
> library(ggforce) # Пакет для малювання правильних багатокутників (трикутників)
> # — Налаштування —
> # Колір фону
> bg_color <- “white”
> # — Функція для створення оточення з трикутників —
> # Вона генерує координати для центрів трикутників, розташованих по колу.
> get_triangles <- function(center_x, center_y, n_triangles, distance, size, angle_offset = 0) {
+     # Кути розташування центрів трикутників навколо центральної фігури
+     pos_angles <- seq(0, 2*pi, length.out = n_triangles + 1)[1:n_triangles]
+     
+     data.frame(
+         x = center_x + cos(pos_angles) * distance,
+         y = center_y + sin(pos_angles) * distance,
+         r = size,
+         # Додаємо обертання для кожного трикутника, щоб вони “дивилися” на центр
+         angle = pos_angles + angle_offset 
+     )
+ }
> # — Параметри —
> # Розмір центральних квадратів (однаковий!)
> sq_size <- 0.15
> # ЛІВА ЧАСТИНА (великі фігури)
> left_x <- 1
> num_left <- 6
> dist_left <- 0.7  # Відстань від центру
> size_left <- 0.4  # Розмір трикутників
> # ПРАВА ЧАСТИНА (малі фігури)
> right_x <- 4
> num_right <- 8
> dist_right <- 0.4 # Відстань від центру
> size_right <- 0.1 # Розмір трикутників
> # — Генерація даних —
> # n=3 для geom_regon означає трикутник
> left_data <- get_triangles(left_x, 1, num_left, dist_left, size_left, angle_offset = pi/num_left)
> right_data <- get_triangles(right_x, 1, num_right, dist_right, size_right, angle_offset = 0)
> # — Візуалізація —
> ggplot() +
+     
+     # 1. Малюємо ЛІВЕ оточення (великі сірі трикутники)
+     # angle = pi/2 повертає трикутник вершиною вгору, sides=3 – трикутник
+     geom_regon(data = left_data, 
+                aes(x0 = x, y0 = y, r = r, angle = pi/2, sides = 3), 
+                fill = “lightgrey”, color = “grey40”, linewidth = 0.5) +
+     
+     # 2. Малюємо ПРАВЕ оточення (малі сірі трикутники)
+     geom_regon(data = right_data, 
+                aes(x0 = x, y0 = y, r = r, angle = pi/2, sides = 3), 
+                fill = “lightgrey”, color = “grey40”, linewidth = 0.5) +
+     
+     # 3. Малюємо ЦЕНТРАЛЬНІ СИНІ КВАДРАТИ (geom_rect використовує координати кутів)
+     # Лівий квадрат (центр: left_x, 1)
+     geom_rect(aes(xmin = left_x – sq_size, xmax = left_x + sq_size, 
+                   ymin = 1 – sq_size, ymax = 1 + sq_size), 
+               fill = “blue”, color = “black”, linewidth = 1) +
+     
+     # Правий квадрат (центр: right_x, 1)
+     geom_rect(aes(xmin = right_x – sq_size, xmax = right_x + sq_size, 
+                   ymin = 1 – sq_size, ymax = 1 + sq_size), 
+               fill = “blue”, color = “black”, linewidth = 1) +
+     
+     # — Налаштування вісі та теми —
+     coord_fixed(ratio = 1, xlim = c(-0.2, 5.2), ylim = c(0, 2)) +
+     theme_void() +
+     labs(title = “Compare the areas of the square on
+          the right and the square on the left”,
+          subtitle = “Explain in writing”) +
+     theme(plot.background = element_rect(fill = bg_color, color = NA),
+           panel.background = element_rect(fill = bg_color, color = NA),
+           plot.title = element_text(hjust = 0.5, face = “bold”, size = 20),
+           plot.subtitle = element_text(hjust = 0.5, size = 16),
+           legend.position = “none”)
> # Переконайтеся, що бібліотеки встановлені: install.packages(c(“ggplot2”, “ggforce”))
> library(ggplot2)
> library(ggforce)
> # — Налаштування кольорів —
> bg_color <- “white”
> center_color <- “orange”   # Новий колір для центру
> surround_color <- “darkgrey”
> # — Параметри ілюзії —
> tri_size <- 0.22  # Розмір центральних трикутників (однаковий для обох)
> # ЛІВА ЧАСТИНА (велике оточення)
> left_x <- 1
> size_left <- 0.5
> dist_left <- 0.8
> # ПРАВА ЧАСТИНА (мале оточення)
> right_x <- 4
> size_right <- 0.12
> dist_right <- 0.4
> # Функція для координат оточення
> get_pos <- function(cx, cy, n, dist) {
+     angles <- seq(0, 2*pi, length.out = n + 1)[1:n]
+     data.frame(x = cx + cos(angles) * dist, y = cy + sin(angles) * dist)
+ }
> left_surround <- get_pos(left_x, 1, 6, dist_left)
> right_surround <- get_pos(right_x, 1, 8, dist_right)
> # — Візуалізація —
> ggplot() +
+     # 1. Оточуючі великі трикутники (зліва)
+     geom_regon(data = left_surround, 
+                aes(x0 = x, y0 = y, r = size_left, angle = pi/2, sides = 3), 
+                fill = surround_color, color = “black”) +
+     
+     # 2. Оточуючі малі трикутники (справа)
+     geom_regon(data = right_surround, 
+                aes(x0 = x, y0 = y, r = size_right, angle = pi/2, sides = 3), 
+                fill = surround_color, color = “black”) +
+     
+     # 3. ЦЕНТРАЛЬНІ ТРИКУТНИКИ (абсолютно однакові)
+     # Лівий
+     geom_regon(aes(x0 = left_x, y0 = 1, r = tri_size, angle = pi/2, sides = 3), 
+                fill = center_color, color = “black”, linewidth = 1) +
+     # Правий
+     geom_regon(aes(x0 = right_x, y0 = 1, r = tri_size, angle = pi/2, sides = 3), 
+                fill = center_color, color = “black”, linewidth = 1) +
+     
+     # — Ваші налаштування заголовків та теми —
+     coord_fixed(xlim = c(-0.2, 5.2), ylim = c(0, 2)) +
+     theme_void() +
+     labs(title = “Compare the areas of the triangle on \nthe right and the triangle on the left”,
+          subtitle = “Explain in writing”) +
+     theme(plot.background = element_rect(fill = bg_color, color = NA),
+           panel.background = element_rect(fill = bg_color, color = NA),
+           plot.title = element_text(hjust = 0.5, face = “bold”, size = 20),
+           plot.subtitle = element_text(hjust = 0.5, size = 16),
+           legend.position = “none”)
> book <- book %>%
+     mutate(
+         condition_clean = recode(condition,
+                                  “control” = “Full digital twin”,
+                                  “generic” = “Partial digital twin”,
+                                  “adaptive” = “Standard feedback”
+         )
+     )
Error: object ‘book’ not found
 
> library(readr)
> library(dplyr)
> book <- read_delim(
+     “/Users/vasylzalizko/Book2026.csv”,
+     delim = “;”,
+     locale = locale(decimal_mark = “,”),
+     show_col_types = FALSE,
+     trim_ws = TRUE
+ )
>                                                                                        
> book <- book %>%
+     mutate(
+         condition_clean = recode(
+             condition,
+             “control” = “Full digital twin”,
+             “generic” = “Partial digital twin”,
+             “adaptive” = “Standard feedback”
+         )
+     )
> table(book$condition, book$condition_clean)
          
           Full digital twin Partial digital twin Standard feedback
  adaptive                 0                    0                39
  control                131                    0                 0
  generic                  0                  110                 0
> book <- book %>%
+   mutate(
+     condition_clean = factor(
+       condition_clean,
+       levels = c(“Full digital twin”, “Partial digital twin”, “Standard feedback”)
+     )
+   )
> library(readr)
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> library(car)
Loading required package: carData
 
Attaching package: ‘car’
 
The following object is masked from ‘package:purrr’:
 
    some
 
The following object is masked from ‘package:dplyr’:
 
    recode
> library(emmeans)
> library(broom)
> book <- read_delim(
+     “/Users/vasylzalizko/Book2026.csv”,
+     delim = “;”,
+     locale = locale(decimal_mark = “,”),
+     show_col_types = FALSE,
+     trim_ws = TRUE
+ )
>                                                                                        
> book <- book %>%
+     mutate(
+         condition_clean = recode(
+             condition,
+             “control” = “Full digital twin”,
+             “generic” = “Partial digital twin”,
+             “adaptive” = “Standard feedback”
+         ),
+         condition_clean = factor(
+             condition_clean,
+             levels = c(“Standard feedback”, “Partial digital twin”, “Full digital twin”)
+         ),
+         delta_HMMI = HMMI_index_post – HMMI_index_pre
+     )
Error in `mutate()`:
ℹ In argument: `condition_clean = recode(…)`.
Caused by error in `recode()`:
! unused arguments (control = “Full digital twin”, generic = “Partial digital twin”, adaptive = “Standard feedback”)
Backtrace:
 1. book %>% …
 3. dplyr:::mutate.data.frame(…)
 4. dplyr:::mutate_cols(.data, dplyr_quosures(…), by)
 6. dplyr:::mutate_col(dots[[i]], data, mask, new_columns)
 7. mask$eval_all_mutate(quo)
 8. dplyr (local) eval()
 
> book <- book %>%
+     mutate(
+         condition_clean = dplyr::recode(
+             condition,
+             “control” = “Full digital twin”,
+             “generic” = “Partial digital twin”,
+             “adaptive” = “Standard feedback”
+         ),
+         condition_clean = factor(
+             condition_clean,
+             levels = c(“Standard feedback”, “Partial digital twin”, “Full digital twin”)
+         ),
+         delta_HMMI = HMMI_index_post – HMMI_index_pre
+     )
> book <- book %>%
+     mutate(
+         condition_clean = case_when(
+             condition == “control”  ~ “Full digital twin”,
+             condition == “generic”  ~ “Partial digital twin”,
+             condition == “adaptive” ~ “Standard feedback”,
+             TRUE ~ as.character(condition)
+         ),
+         condition_clean = factor(
+             condition_clean,
+             levels = c(“Standard feedback”, “Partial digital twin”, “Full digital twin”)
+         ),
+         delta_HMMI = HMMI_index_post – HMMI_index_pre
+     )
> find(“recode”)
[1] “package:car”   “package:dplyr”
> book <- book %>%
+     mutate(
+         condition_clean = dplyr::recode(
+             condition,
+             “control” = “Full digital twin”,
+             “generic” = “Partial digital twin”,
+             “adaptive” = “Standard feedback”
+         ),
+         condition_clean = factor(
+             condition_clean,
+             levels = c(“Standard feedback”, “Partial digital twin”, “Full digital twin”)
+         ),
+         delta_HMMI = HMMI_index_post – HMMI_index_pre
+     )
> table(book$condition, book$condition_clean)
          
           Standard feedback Partial digital twin Full digital twin
  adaptive                39                    0                 0
  control                  0                    0               131
  generic                  0                  110                 0
> book <- book %>%
+     mutate(
+         condition_clean = case_when(
+             condition == “control”  ~ “Full digital twin”,
+             condition == “generic”  ~ “Partial digital twin”,
+             condition == “adaptive” ~ “Standard feedback”,
+             TRUE ~ as.character(condition)
+         ),
+         condition_clean = factor(
+             condition_clean,
+             levels = c(“Standard feedback”, “Partial digital twin”, “Full digital twin”)
+         ),
+         delta_HMMI = HMMI_index_post – HMMI_index_pre
+     )
> anova_pre <- aov(HMMI_index_pre ~ condition_clean, data = book)
> summary(anova_pre)
                 Df Sum Sq Mean Sq F value Pr(>F)
condition_clean   2  0.045 0.02229   1.031  0.358
Residuals       277  5.989 0.02162               
> anova_delta <- aov(delta_HMMI ~ condition_clean, data = book)
> summary(anova_delta)
                 Df Sum Sq Mean Sq F value Pr(>F)    
condition_clean   2  4.363  2.1814   97.66 <2e-16 ***
Residuals       277  6.187  0.0223                   
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
> library(ggplot2)
> library(dplyr)
> fig1 <- ggplot(book, aes(x = condition_clean, y = HMMI_index_pre)) +
+     geom_boxplot(width = 0.65, outlier.shape = 16, outlier.size = 1.8) +
+     labs(
+         title = “Pretest HMMI by instructional condition”,
+         x = “Instructional condition”,
+         y = “Pretest HMMI”
+     ) +
+     theme_minimal(base_size = 13) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         axis.text.x = element_text(angle = 12, hjust = 1)
+     )
> fig1
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> book_long_sub <- book %>%
+     select(condition_clean, V_index_pre, T_index_pre, M_index_pre3) %>%
+     pivot_longer(
+         cols = c(V_index_pre, T_index_pre, M_index_pre3),
+         names_to = “subindex”,
+         values_to = “value”
+     ) %>%
+     mutate(
+         subindex = dplyr::recode(
+             subindex,
+             “V_index_pre” = “Visual”,
+             “T_index_pre” = “Textual”,
+             “M_index_pre3” = “Mixed”
+         )
+     )
> fig2 <- ggplot(book_long_sub, aes(x = subindex, y = value, fill = condition_clean)) +
+     stat_summary(fun = mean, geom = “bar”, position = position_dodge(width = 0.8), width = 0.7) +
+     stat_summary(
+         fun.data = mean_se,
+         geom = “errorbar”,
+         position = position_dodge(width = 0.8),
+         width = 0.18
+     ) +
+     labs(
+         title = “Pretest modality-specific subindices by instructional condition”,
+         x = “Subindex”,
+         y = “Mean pretest value”,
+         fill = “Condition”
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “bottom”
+     )
> fig2
> library(ggplot2)
> library(dplyr)
> library(tidyr)
> library(patchwork)
> # —————————–
> # PANEL A: schematic prior evidence (adapted concept, not copied figure)
> # —————————–
> rho_schematic <- tibble::tibble(
+     vis_type = c(“Axis\nmanipulation”, “Dual\naxes”, “3D\ndistortion”, “Salience\nbias”, “Compressed\nscale”),
+     accuracy_nonmisleading = c(0.94, 0.90, 0.88, 0.91, 0.89),
+     accuracy_misleading    = c(0.58, 0.36, 0.29, 0.47, 0.41)
+ ) %>%
+     pivot_longer(
+         cols = starts_with(“accuracy”),
+         names_to = “condition”,
+         values_to = “accuracy”
+     ) %>%
+     mutate(
+         condition = recode(
+             condition,
+             “accuracy_nonmisleading” = “Non-misleading”,
+             “accuracy_misleading” = “Misleading”
+         )
+     )
Error in `mutate()`:
ℹ In argument: `condition = recode(…)`.
Caused by error in `recode()`:
! unused arguments (accuracy_nonmisleading = “Non-misleading”, accuracy_misleading = “Misleading”)
Backtrace:
 1. … %>% …
 3. dplyr:::mutate.data.frame(…)
 4. dplyr:::mutate_cols(.data, dplyr_quosures(…), by)
 6. dplyr:::mutate_col(dots[[i]], data, mask, new_columns)
 7. mask$eval_all_mutate(quo)
 8. dplyr (local) eval()
 
> library(ggplot2)
> library(dplyr)
> library(tidyr)
> library(patchwork)
> # —————————–
> # PANEL A: schematic prior evidence (adapted concept, not copied figure)
> # —————————–
> rho_schematic <- tibble::tibble(
+     vis_type = c(“Axis\nmanipulation”, “Dual\naxes”, “3D\ndistortion”, “Salience\nbias”, “Compressed\nscale”),
+     accuracy_nonmisleading = c(0.94, 0.90, 0.88, 0.91, 0.89),
+     accuracy_misleading    = c(0.58, 0.36, 0.29, 0.47, 0.41)
+ ) %>%
+     pivot_longer(
+         cols = starts_with(“accuracy”),
+         names_to = “condition”,
+         values_to = “accuracy”
+     ) %>%
+     mutate(
+         condition = dplyr::recode(
+             condition,
+             “accuracy_nonmisleading” = “Non-misleading”,
+             “accuracy_misleading” = “Misleading”
+         ),
+         condition = factor(condition, levels = c(“Misleading”, “Non-misleading”))
+     )
> pA <- ggplot(rho_schematic, aes(x = vis_type, y = accuracy, fill = condition)) +
+     geom_col(position = position_dodge(width = 0.8), width = 0.7) +
+     labs(
+         title = “A. Prior evidence (adapted from Rho/Rau)”,
+         x = “Visualization type”,
+         y = “Interpretation accuracy”,
+         fill = NULL
+     ) +
+     theme_minimal(base_size = 11) +
+     theme(
+         plot.title = element_text(face = “bold”, size = 11),
+         axis.text.x = element_text(angle = 25, hjust = 1),
+         legend.position = “bottom”
+     )
> # —————————–
> # PANEL B: your real results (pre-post HMMI by condition)
> # —————————–
> book_long_hmmi <- book %>%
+     select(learner_id, condition_clean, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(
+         cols = c(HMMI_index_pre, HMMI_index_post),
+         names_to = “moment”,
+         values_to = “HMMI”
+     ) %>%
+     mutate(
+         moment = dplyr::recode(
+             moment,
+             “HMMI_index_pre” = “Pretest”,
+             “HMMI_index_post” = “Posttest”
+         ),
+         moment = factor(moment, levels = c(“Pretest”, “Posttest”))
+     )
> pB <- ggplot(book_long_hmmi, aes(x = moment, y = HMMI, group = condition_clean, color = condition_clean)) +
+     stat_summary(fun = mean, geom = “line”, linewidth = 1.1) +
+     stat_summary(fun = mean, geom = “point”, size = 2.8) +
+     labs(
+         title = “B. Present study: condition-sensitive HMMI outcomes”,
+         x = NULL,
+         y = “Mean HMMI”,
+         color = NULL
+     ) +
+     theme_minimal(base_size = 11) +
+     theme(
+         plot.title = element_text(face = “bold”, size = 11),
+         legend.position = “bottom”
+     )
> # —————————–
> # COMBINE
> # —————————–
> fig_combined <- pA + pB + plot_layout(widths = c(1.05, 1))
> fig_combined
> library(ggplot2)
> library(dplyr)
> library(tidyr)
> library(patchwork)
> # —————————–
> # PANEL A: your three subindices
> # —————————–
> book_long_sub <- book %>%
+     select(condition_clean, V_index_pre, T_index_pre, M_index_pre3) %>%
+     pivot_longer(
+         cols = c(V_index_pre, T_index_pre, M_index_pre3),
+         names_to = “subindex”,
+         values_to = “value”
+     ) %>%
+     mutate(
+         subindex = dplyr::recode(
+             subindex,
+             “V_index_pre” = “Visual”,
+             “T_index_pre” = “Textual”,
+             “M_index_pre3” = “Mixed”
+         ),
+         subindex = factor(subindex, levels = c(“Visual”, “Textual”, “Mixed”))
+     )
> pA <- ggplot(book_long_sub, aes(x = subindex, y = value, fill = condition_clean)) +
+     stat_summary(fun = mean, geom = “bar”, position = position_dodge(width = 0.8), width = 0.7) +
+     stat_summary(
+         fun.data = mean_se,
+         geom = “errorbar”,
+         position = position_dodge(width = 0.8),
+         width = 0.18
+     ) +
+     labs(
+         title = “A. Pretest modality-specific subindices”,
+         x = NULL,
+         y = “Mean pretest value”,
+         fill = NULL
+     ) +
+     theme_minimal(base_size = 11) +
+     theme(
+         plot.title = element_text(face = “bold”, size = 11),
+         legend.position = “bottom”
+     )
> # —————————–
> # PANEL B: conceptual list of illusions/effects
> # —————————–
> illus_df <- tibble::tibble(
+     x = 1,
+     y = c(8, 7, 6, 5, 4, 3, 2, 1),
+     label = c(
+         “Ebbinghaus illusion”,
+         “Müller–Lyer illusion”,
+         “Ponzo illusion”,
+         “Delboeuf illusion”,
+         “Poggendorff illusion”,
+         “Axis truncation”,
+         “Dual-axis distortion”,
+         “Salience bias”
+     )
+ )
> pB <- ggplot(illus_df, aes(x = x, y = y, label = label)) +
+     geom_text(hjust = 0, size = 3.8) +
+     xlim(1, 2.8) +
+     ylim(0.5, 8.5) +
+     labs(
+         title = “B. Examples of visual misleadingness sources”
+     ) +
+     theme_void(base_size = 11) +
+     theme(
+         plot.title = element_text(face = “bold”, size = 11, hjust = 0)
+     )
> # —————————–
> # COMBINE
> # —————————–
> fig_indices_illusions <- pA + pB + plot_layout(widths = c(1.5, 1))
> fig_indices_illusions
> library(ggplot2)
> library(dplyr)
> library(tidyr)
> subindex_overall <- book %>%
+     select(V_index_pre, T_index_pre, M_index_pre3) %>%
+     pivot_longer(
+         cols = everything(),
+         names_to = “subindex”,
+         values_to = “value”
+     ) %>%
+     mutate(
+         subindex = dplyr::recode(
+             subindex,
+             “V_index_pre” = “Visual”,
+             “T_index_pre” = “Textual”,
+             “M_index_pre3” = “Mixed”
+         ),
+         subindex = factor(subindex, levels = c(“Visual”, “Textual”, “Mixed”))
+     )
> fig2_overall <- ggplot(subindex_overall, aes(x = subindex, y = value)) +
+     stat_summary(fun = mean, geom = “bar”, width = 0.62) +
+     stat_summary(
+         fun.data = mean_se,
+         geom = “errorbar”,
+         width = 0.18
+     ) +
+     labs(
+         title = “Pretest modality-specific subindices”,
+         x = “Subindex”,
+         y = “Mean pretest value”
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “none”
+     )
> fig2_overall
> library(ggplot2)
> library(dplyr)
> library(tidyr)
> subindex_overall <- book %>%
+     select(V_index_pre, T_index_pre, M_index_pre3) %>%
+     pivot_longer(
+         cols = everything(),
+         names_to = “subindex”,
+         values_to = “value”
+     ) %>%
+     mutate(
+         subindex = dplyr::recode(
+             subindex,
+             “V_index_pre” = “Visual”,
+             “T_index_pre” = “Textual”,
+             “M_index_pre3” = “Mixed”
+         ),
+         subindex = factor(subindex, levels = c(“Visual”, “Textual”, “Mixed”))
+     )
> fig2_overall <- ggplot(subindex_overall, aes(x = subindex, y = value, fill = subindex)) +
+     stat_summary(fun = mean, geom = “bar”, width = 0.62) +
+     stat_summary(
+         fun.data = mean_se,
+         geom = “errorbar”,
+         width = 0.18
+     ) +
+     scale_y_continuous(limits = c(0.4, 0.8), expand = c(0, 0)) +
+     labs(
+         title = “Pretest modality-specific subindices”,
+         x = “Subindex”,
+         y = “Mean pretest value”
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “none”
+     )
> fig2_overall
Warning messages:
1: Removed 200 rows containing non-finite outside the scale range (`stat_summary()`). 
2: Removed 200 rows containing non-finite outside the scale range (`stat_summary()`). 
3: Removed 3 rows containing missing values or values outside the scale range (`geom_bar()`). 
 
> library(ggplot2)
> library(dplyr)
> library(tidyr)
> subindex_overall <- book %>%
+     select(V_index_pre, T_index_pre, M_index_pre3) %>%
+     pivot_longer(
+         cols = everything(),
+         names_to = “subindex”,
+         values_to = “value”
+     ) %>%
+     mutate(
+         subindex = dplyr::recode(
+             subindex,
+             “V_index_pre” = “Visual”,
+             “T_index_pre” = “Textual”,
+             “M_index_pre3” = “Mixed”
+         ),
+         subindex = factor(subindex, levels = c(“Visual”, “Textual”, “Mixed”))
+     )
> subindex_summary <- subindex_overall %>%
+     group_by(subindex) %>%
+     summarise(
+         mean_value = mean(value, na.rm = TRUE),
+         se_value = sd(value, na.rm = TRUE) / sqrt(sum(!is.na(value))),
+         .groups = “drop”
+     )
> fig2_overall <- ggplot(subindex_summary, aes(x = subindex, y = mean_value, fill = subindex)) +
+     geom_col(width = 0.62) +
+     geom_errorbar(
+         aes(ymin = mean_value – se_value, ymax = mean_value + se_value),
+         width = 0.18
+     ) +
+     coord_cartesian(ylim = c(0.4, 0.8)) +
+     labs(
+         title = “Pretest modality-specific subindices”,
+         x = “Subindex”,
+         y = “Mean pretest value”
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “none”
+     )
> fig2_overall
> library(ggplot2)
> library(dplyr)
> library(tidyr)
> subindex_overall <- book %>%
+     select(V_index_pre, T_index_pre, M_index_pre3) %>%
+     pivot_longer(
+         cols = everything(),
+         names_to = “subindex”,
+         values_to = “value”
+     ) %>%
+     mutate(
+         subindex = dplyr::recode(
+             subindex,
+             “V_index_pre” = “Visual”,
+             “T_index_pre” = “Textual”,
+             “M_index_pre3” = “Mixed”
+         ),
+         subindex = factor(subindex, levels = c(“Visual”, “Textual”, “Mixed”))
+     )
> subindex_summary <- subindex_overall %>%
+     group_by(subindex) %>%
+     summarise(
+         mean_value = mean(value, na.rm = TRUE),
+         se_value = sd(value, na.rm = TRUE) / sqrt(sum(!is.na(value))),
+         .groups = “drop”
+     )
> fig2_overall <- ggplot(subindex_summary, aes(x = subindex, y = mean_value, fill = subindex)) +
+     geom_col(width = 0.62) +
+     geom_errorbar(
+         aes(ymin = mean_value – se_value, ymax = mean_value + se_value),
+         width = 0.18
+     ) +
+     coord_cartesian(ylim = c(0.4, 0.7)) +
+     labs(
+         title = “Pretest modality-specific subindices”,
+         x = “Subindex”,
+         y = “Mean pretest value”
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “none”
+     )
> fig2_overall
> library(ggplot2)
> library(dplyr)
> library(tidyr)
> subindex_overall <- book %>%
+     select(V_index_pre, T_index_pre, M_index_pre3) %>%
+     pivot_longer(
+         cols = everything(),
+         names_to = “subindex”,
+         values_to = “value”
+     ) %>%
+     mutate(
+         subindex = dplyr::recode(
+             subindex,
+             “V_index_pre” = “Visual”,
+             “T_index_pre” = “Textual”,
+             “M_index_pre3” = “Mixed”
+         ),
+         subindex = factor(subindex, levels = c(“Visual”, “Textual”, “Mixed”))
+     )
> subindex_summary <- subindex_overall %>%
+     group_by(subindex) %>%
+     summarise(
+         mean_value = mean(value, na.rm = TRUE),
+         se_value = sd(value, na.rm = TRUE) / sqrt(sum(!is.na(value))),
+         .groups = “drop”
+     )
> fig2_overall <- ggplot(subindex_summary, aes(x = subindex, y = mean_value, fill = subindex)) +
+     geom_col(width = 0.62) +
+     geom_errorbar(
+         aes(ymin = mean_value – se_value, ymax = mean_value + se_value),
+         width = 0.18
+     ) +
+     coord_cartesian(ylim = c(0.4, 0.6)) +
+     labs(
+         title = “Pretest modality-specific subindices”,
+         x = “Subindex”,
+         y = “Mean pretest value”
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “none”
+     )
> fig2_overall
> library(ggplot2)
> library(dplyr)
> library(tidyr)
> subindex_overall <- book %>%
+     select(V_index_pre, T_index_pre, M_index_pre3) %>%
+     pivot_longer(
+         cols = everything(),
+         names_to = “subindex”,
+         values_to = “value”
+     ) %>%
+     mutate(
+         subindex = dplyr::recode(
+             subindex,
+             “V_index_pre” = “Visual”,
+             “T_index_pre” = “Textual”,
+             “M_index_pre3” = “Mixed”
+         ),
+         subindex = factor(subindex, levels = c(“Visual”, “Textual”, “Mixed”))
+     )
> subindex_summary <- subindex_overall %>%
+     group_by(subindex) %>%
+     summarise(
+         mean_value = mean(value, na.rm = TRUE),
+         se_value = sd(value, na.rm = TRUE) / sqrt(sum(!is.na(value))),
+         .groups = “drop”
+     )
> fig2_overall <- ggplot(subindex_summary, aes(x = subindex, y = mean_value, fill = subindex)) +
+     geom_col(width = 0.62) +
+     geom_errorbar(
+         aes(ymin = mean_value – se_value, ymax = mean_value + se_value),
+         width = 0.18
+     ) +
+     coord_cartesian(ylim = c(0.4, 0.7)) +
+     labs(
+         title = “Pretest modality-specific subindices”,
+         x = “Subindex”,
+         y = “Mean pretest value”
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “none”
+     )
> fig2_overall
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> book_long_hmmi <- book %>%
+     select(learner_id, condition_clean, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(
+         cols = c(HMMI_index_pre, HMMI_index_post),
+         names_to = “moment”,
+         values_to = “HMMI”
+     ) %>%
+     mutate(
+         moment = dplyr::recode(
+             moment,
+             “HMMI_index_pre” = “Pretest”,
+             “HMMI_index_post” = “Posttest”
+         ),
+         moment = factor(moment, levels = c(“Pretest”, “Posttest”))
+     )
> hmmi_summary <- book_long_hmmi %>%
+     group_by(condition_clean, moment) %>%
+     summarise(
+         mean_HMMI = mean(HMMI, na.rm = TRUE),
+         se_HMMI = sd(HMMI, na.rm = TRUE) / sqrt(sum(!is.na(HMMI))),
+         .groups = “drop”
+     )
> fig_prepost <- ggplot(hmmi_summary, aes(x = moment, y = mean_HMMI, group = condition_clean, color = condition_clean)) +
+     geom_line(linewidth = 1.1) +
+     geom_point(size = 2.8) +
+     geom_errorbar(aes(ymin = mean_HMMI – se_HMMI, ymax = mean_HMMI + se_HMMI), width = 0.08) +
+     labs(
+         title = “Pretest–posttest HMMI by instructional condition”,
+         x = NULL,
+         y = “Mean HMMI”,
+         color = NULL
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “bottom”
+     )
> fig_prepost
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> # якщо ще не перекодовано групи
> book <- book %>%
+     mutate(
+         condition_clean = dplyr::recode(
+             condition,
+             “control”  = “Full digital twin”,
+             “generic”  = “Partial digital twin”,
+             “adaptive” = “Standard feedback”
+         ),
+         condition_clean = factor(
+             condition_clean,
+             levels = c(“Standard feedback”, “Partial digital twin”, “Full digital twin”)
+         )
+     )
> # long format
> book_long_hmmi <- book %>%
+     select(learner_id, condition_clean, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(
+         cols = c(HMMI_index_pre, HMMI_index_post),
+         names_to = “moment”,
+         values_to = “HMMI”
+     ) %>%
+     mutate(
+         moment = dplyr::recode(
+             moment,
+             “HMMI_index_pre”  = “Pretest”,
+             “HMMI_index_post” = “Posttest”
+         ),
+         moment = factor(moment, levels = c(“Pretest”, “Posttest”))
+     )
> # summary table
> hmmi_summary <- book_long_hmmi %>%
+     group_by(condition_clean, moment) %>%
+     summarise(
+         mean_HMMI = mean(HMMI, na.rm = TRUE),
+         se_HMMI   = sd(HMMI, na.rm = TRUE) / sqrt(sum(!is.na(HMMI))),
+         .groups = “drop”
+     )
> # clean journal-style figure
> fig_prepost_clean <- ggplot(
+     hmmi_summary,
+     aes(x = moment, y = mean_HMMI, group = condition_clean, color = condition_clean)
+ ) +
+     geom_line(linewidth = 1.1) +
+     geom_point(size = 3) +
+     geom_errorbar(
+         aes(ymin = mean_HMMI – se_HMMI, ymax = mean_HMMI + se_HMMI),
+         width = 0.08,
+         linewidth = 0.7
+     ) +
+     facet_wrap(~ condition_clean, nrow = 1) +
+     labs(
+         title = “Pretest–posttest change in HMMI by instructional condition”,
+         x = NULL,
+         y = “Mean HMMI”,
+         color = NULL
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “none”,
+         strip.text = element_text(face = “bold”)
+     )
> fig_prepost_clean
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> # якщо ще не перекодовано групи
> book <- book %>%
+     mutate(
+         condition_clean = dplyr::recode(
+             condition,
+             “control”  = “Full digital twin”,
+             “generic”  = “Partial digital twin”,
+             “adaptive” = “Standard feedback”
+         ),
+         condition_clean = factor(
+             condition_clean,
+             levels = c(“Standard feedback”, “Partial digital twin”, “Full digital twin”)
+         )
+     )
> # long format
> book_long_hmmi <- book %>%
+     select(learner_id, condition_clean, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(
+         cols = c(HMMI_index_pre, HMMI_index_post),
+         names_to = “moment”,
+         values_to = “HMMI”
+     ) %>%
+     mutate(
+         moment = dplyr::recode(
+             moment,
+             “HMMI_index_pre”  = “Pretest”,
+             “HMMI_index_post” = “Posttest”
+         ),
+         moment = factor(moment, levels = c(“Pretest”, “Posttest”))
+     )
> # summary table
> hmmi_summary <- book_long_hmmi %>%
+     group_by(condition_clean, moment) %>%
+     summarise(
+         mean_HMMI = mean(HMMI, na.rm = TRUE),
+         se_HMMI   = sd(HMMI, na.rm = TRUE) / sqrt(sum(!is.na(HMMI))),
+         .groups = “drop”
+     )
> # clean journal-style figure
> fig_prepost_clean <- ggplot(
+     hmmi_summary,
+     aes(x = moment, y = mean_HMMI, group = condition_clean, color = condition_clean)
+ ) +
+     geom_line(linewidth = 1.1) +
+     geom_point(size = 3) +
+     geom_errorbar(
+         aes(ymin = mean_HMMI – se_HMMI, ymax = mean_HMMI + se_HMMI),
+         width = 0.08,
+         linewidth = 0.7
+     ) +
+     facet_wrap(~ condition_clean, nrow = 1) +
+     labs(
+         title = “Pretest–posttest change in HMMI by instructional condition”,
+         x = NULL,
+         y = “Mean HMMI”,
+         color = NULL
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “none”,
+         strip.text = element_text(face = “bold”)
+     )
> fig_prepost_clean
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> fig_points <- ggplot(book_long, aes(x = moment, y = HMMI)) +
+     geom_violin(fill = “gray90”, color = NA, width = 0.9) +
+     geom_boxplot(width = 0.18, outlier.shape = NA, fill = “white”) +
+     geom_jitter(width = 0.08, alpha = 0.22, size = 1) +
+     stat_summary(aes(group = 1), fun = mean, geom = “point”, size = 3, shape = 18) +
+     facet_wrap(~ condition_clean, nrow = 1) +
+     labs(
+         title = “Distribution of individual HMMI values before and after intervention”,
+         x = NULL,
+         y = “HMMI”
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         strip.text = element_text(face = “bold”)
+     )
Error: object ‘book_long’ not found
 
> imal(base_size = 12) +
+     +     theme(
+         +         plot.title = element_text(face = “bold”),
Error: unexpected ‘=’ in:
”    +     theme(
        +         plot.title =”
 
> library(dplyr)
> library(tidyr)
> library(ggplot2)
> book <- book %>%
+     mutate(
+         condition_clean = dplyr::recode(
+             condition,
+             “control”  = “Full digital twin”,
+             “generic”  = “Partial digital twin”,
+             “adaptive” = “Standard feedback”
+         ),
+         condition_clean = factor(
+             condition_clean,
+             levels = c(“Standard feedback”, “Partial digital twin”, “Full digital twin”)
+         )
+     )
> book_long <- book %>%
+     select(learner_id, condition_clean, HMMI_index_pre, HMMI_index_post) %>%
+     pivot_longer(
+         cols = c(HMMI_index_pre, HMMI_index_post),
+         names_to = “moment”,
+         values_to = “HMMI”
+     ) %>%
+     mutate(
+         moment = dplyr::recode(
+             moment,
+             “HMMI_index_pre” = “Pretest”,
+             “HMMI_index_post” = “Posttest”
+         ),
+         moment = factor(moment, levels = c(“Pretest”, “Posttest”))
+     )
> fig_points <- ggplot(book_long, aes(x = moment, y = HMMI)) +
+     geom_violin(fill = “gray90”, color = NA, width = 0.9) +
+     geom_boxplot(width = 0.18, outlier.shape = NA, fill = “white”) +
+     geom_jitter(width = 0.08, alpha = 0.22, size = 1) +
+     stat_summary(aes(group = 1), fun = mean, geom = “point”, size = 3, shape = 18) +
+     facet_wrap(~ condition_clean, nrow = 1) +
+     labs(
+         title = “Distribution of individual HMMI values before and after intervention”,
+         x = NULL,
+         y = “HMMI”
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         strip.text = element_text(face = “bold”)
+     )
> fig_points
> library(dplyr)
> library(ggplot2)
> book <- book %>%
+     mutate(
+         condition_clean = dplyr::recode(
+             condition,
+             “control”  = “Full digital twin”,
+             “generic”  = “Partial digital twin”,
+             “adaptive” = “Standard feedback”
+         ),
+         condition_clean = factor(
+             condition_clean,
+             levels = c(“Standard feedback”, “Partial digital twin”, “Full digital twin”)
+         ),
+         gain_HMMI = HMMI_index_post – HMMI_index_pre
+     )
> fig_gain_students <- ggplot(book, aes(x = condition_clean, y = gain_HMMI, fill = condition_clean, color = condition_clean)) +
+     geom_violin(alpha = 0.35, width = 0.95, linewidth = 0.4) +
+     geom_boxplot(width = 0.16, outlier.shape = NA, alpha = 0.55, linewidth = 0.4) +
+     geom_jitter(width = 0.08, alpha = 0.28, size = 1.2) +
+     stat_summary(fun = mean, geom = “point”, size = 3.2, shape = 18, color = “black”) +
+     scale_fill_manual(values = c(
+         “Standard feedback” = “#F4B6C2”,
+         “Partial digital twin” = “#BFD7EA”,
+         “Full digital twin” = “#CDECCF”
+     )) +
+     scale_color_manual(values = c(
+         “Standard feedback” = “#E89AAE”,
+         “Partial digital twin” = “#8FB9D6”,
+         “Full digital twin” = “#97C89B”
+     )) +
+     labs(
+         title = “Individual HMMI gains by instructional condition”,
+         x = NULL,
+         y = “Gain in HMMI (post – pre)”,
+         fill = NULL,
+         color = NULL
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “none”,
+         axis.text.x = element_text(angle = 10, hjust = 1)
+     )
> fig_gain_students
> library(dplyr)
> library(ggplot2)
> fig_visual_grade <- ggplot(book, aes(x = grade_group, y = V_index_pre, fill = grade_group, color = grade_group)) +
+     geom_violin(alpha = 0.30, width = 0.9, linewidth = 0.4) +
+     geom_boxplot(width = 0.16, outlier.shape = NA, alpha = 0.55, linewidth = 0.4) +
+     geom_jitter(width = 0.08, alpha = 0.18, size = 1) +
+     stat_summary(fun = mean, geom = “point”, size = 3.2, shape = 18, color = “black”) +
+     scale_fill_manual(values = c(
+         “5-8” = “#F4C2C2”,
+         “9-11” = “#BFD7EA”
+     )) +
+     scale_color_manual(values = c(
+         “5-8” = “#D99A9A”,
+         “9-11” = “#8FB9D6”
+     )) +
+     labs(
+         title = “Visual pretest subindex by grade group”,
+         x = “Grade group”,
+         y = “Visual pretest subindex”,
+         fill = NULL,
+         color = NULL
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “none”
+     )
> fig_visual_grade
> library(dplyr)
> library(ggplot2)
> visual_grade_summary <- book %>%
+     group_by(grade_group) %>%
+     summarise(
+         mean_V = mean(V_index_pre, na.rm = TRUE),
+         se_V   = sd(V_index_pre, na.rm = TRUE) / sqrt(sum(!is.na(V_index_pre))),
+         .groups = “drop”
+     )
> fig_visual_grade <- ggplot(book, aes(x = grade_group, y = V_index_pre, color = grade_group)) +
+     geom_jitter(width = 0.08, alpha = 0.22, size = 1.6) +
+     geom_errorbar(
+         data = visual_grade_summary,
+         aes(x = grade_group, ymin = mean_V – se_V, ymax = mean_V + se_V),
+         width = 0.10,
+         linewidth = 0.8,
+         inherit.aes = FALSE,
+         color = “black”
+     ) +
+     geom_point(
+         data = visual_grade_summary,
+         aes(x = grade_group, y = mean_V),
+         inherit.aes = FALSE,
+         size = 3.4,
+         shape = 16,
+         color = “black”
+     ) +
+     scale_color_manual(values = c(
+         “5-8” = “#D99A9A”,
+         “9-11” = “#8FB9D6”
+     )) +
+     labs(
+         title = “Visual pretest subindex by grade group”,
+         x = “Grade group”,
+         y = “Visual pretest subindex”,
+         color = NULL
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”),
+         legend.position = “none”
+     )
> fig_visual_grade
> library(dplyr)
> library(ggplot2)
> # якщо gender має пропуски або різні написи, можна трохи підчистити
> book_plot <- book %>%
+     mutate(
+         gender_clean = case_when(
+             gender %in% c(“Male”, “male”, “M”, “m”, “boy”, “Boy”) ~ “Boys”,
+             gender %in% c(“Female”, “female”, “F”, “f”, “girl”, “Girl”) ~ “Girls”,
+             TRUE ~ “Unknown”
+         ),
+         gender_clean = factor(gender_clean, levels = c(“Girls”, “Boys”, “Unknown”))
+     )
> visual_grade_summary <- book_plot %>%
+     group_by(grade_group) %>%
+     summarise(
+         mean_V = mean(V_index_pre, na.rm = TRUE),
+         se_V   = sd(V_index_pre, na.rm = TRUE) / sqrt(sum(!is.na(V_index_pre))),
+         .groups = “drop”
+     )
> fig_visual_grade_gender <- ggplot(
+     book_plot,
+     aes(x = grade_group, y = V_index_pre, color = grade_group, shape = gender_clean)
+ ) +
+     geom_jitter(width = 0.08, alpha = 0.28, size = 1.8) +
+     geom_errorbar(
+         data = visual_grade_summary,
+         aes(x = grade_group, ymin = mean_V – se_V, ymax = mean_V + se_V),
+         inherit.aes = FALSE,
+         width = 0.10,
+         linewidth = 0.8,
+         color = “black”
+     ) +
+     geom_point(
+         data = visual_grade_summary,
+         aes(x = grade_group, y = mean_V),
+         inherit.aes = FALSE,
+         size = 3.6,
+         shape = 16,
+         color = “black”
+     ) +
+     scale_color_manual(values = c(
+         “5-8” = “#D99A9A”,
+         “9-11” = “#8FB9D6”
+     )) +
+     scale_shape_manual(values = c(
+         “Girls” = 16,
+         “Boys” = 17,
+         “Unknown” = 1
+     )) +
+     labs(
+         title = “Visual pretest subindex by grade group and gender”,
+         x = “Grade group”,
+         y = “Visual pretest subindex”,
+         color = “Grade group”,
+         shape = “Gender”
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”)
+     )
> fig_visual_grade_gender
> library(dplyr)
> library(ggplot2)
> book_plot <- book %>%
+     mutate(
+         gender_clean = case_when(
+             gender %in% c(“Male”, “male”, “M”, “m”, “boy”, “Boy”) ~ “Boys”,
+             gender %in% c(“Female”, “female”, “F”, “f”, “girl”, “Girl”) ~ “Girls”,
+             TRUE ~ “Unknown”
+         ),
+         gender_clean = factor(gender_clean, levels = c(“Girls”, “Boys”, “Unknown”))
+     )
> gender_grade_summary <- book_plot %>%
+     filter(gender_clean != “Unknown”) %>%
+     group_by(grade_group, gender_clean) %>%
+     summarise(
+         mean_V = mean(V_index_pre, na.rm = TRUE),
+         se_V   = sd(V_index_pre, na.rm = TRUE) / sqrt(sum(!is.na(V_index_pre))),
+         .groups = “drop”
+     )
> fig_visual_grade_gender2 <- ggplot(
+     gender_grade_summary,
+     aes(x = grade_group, y = mean_V, color = grade_group, shape = gender_clean)
+ ) +
+     geom_point(
+         position = position_dodge(width = 0.18),
+         size = 3.2
+     ) +
+     geom_errorbar(
+         aes(ymin = mean_V – se_V, ymax = mean_V + se_V),
+         position = position_dodge(width = 0.18),
+         width = 0.08,
+         linewidth = 0.9
+     ) +
+     scale_color_manual(values = c(
+         “5-8” = “#D73027”,
+         “9-11” = “#1F78B4”
+     )) +
+     scale_shape_manual(values = c(
+         “Girls” = 16,
+         “Boys” = 17
+     )) +
+     labs(
+         title = “Visual pretest subindex by grade group and gender”,
+         x = “Grade group”,
+         y = “Mean visual pretest subindex”,
+         color = “Grade group”,
+         shape = “Gender”
+     ) +
+     theme_minimal(base_size = 12) +
+     theme(
+         plot.title = element_text(face = “bold”)
+     )
> fig_visual_grade_gender2
> library(dplyr)
> library(ggplot2)
> book_plot <- book %>%
+     mutate(
+         gender_clean = case_when(
+             gender %in% c(“Male”, “male”, “M”, “m”, “boy”, “Boy”) ~ “Boys”,
+             gender %in% c(“Female”, “female”, “F”, “f”, “girl”, “Girl”) ~ “Girls”,
+             TRUE ~ “Unknown”
+         ),
+         gender_clean = factor(gender_clean, levels = c(“Girls”, “Boys”, “Unknown”))
+     )
> visual_grade_summary <- book_plot %>%
+     group_by(grade_group) %>%
+     summarise(
+         mean_V = mean(V_index_pre, na.rm = TRUE),
+         se_V   = sd(V_index_pre, na.rm = TRUE) / sqrt(sum(!is.na(V_index_pre))),
+         .groups = “drop”
+     )
> fig_visual_grade_gender_scatter <- ggplot(
+     book_plot,
+     aes(x = grade_group, y = V_index_pre, color = grade_group, shape = gender_clean)
+ ) +
+     geom_jitter(width = 0.10, alpha = 0.40, size = 2.0) +
+     geom_errorbar(
+         data = visual_grade_summary,
+         aes(x = grade_group, ymin = mean_V – se_V, ymax = mean_V + se_V),
+         inherit.aes = FALSE,
+         width = 0.10,
+         linewidth = 0.9,
+         color = “black”
+     ) +
+     geom_point(
+         data = visual_grade_summary,
+         aes(x = grade_group, y = mean_V),
+         inherit.aes = FALSE,
+         size = 3.8,
+         shape = 18,
+         color = “black”
+     ) +
+     scale_color_manual(values = c(
+         “5-8” = “#C62828”,
+         “9-11” = “#1565C0”
+     )) +
+     scale_shape_manual(values = c(
+         “Girls” = 16,
+         “Boys” = 17,
+         “Unknown” = 1
+     )) +
+     labs(
+         title = “Visual pretest subindex by grade group and gender”,
+         x = “Grade group”,
+         y = “Visual pretest subindex”,
+         color = “Grade group”,
+         shape = “Gender”
+     ) +
+     theme_minimal(base_size = 12)
Mriia Research Lab Multimodal Cognitive Digital Twins HMMI / PRE / POST

Multimodal Cognitive Digital Twins Мультимодальні когнітивні цифрові двійники

Тут зберігаються матеріали експерименту, R code, PRE/POST результати, структура тестів, а також обчислення Human Multimodal Misleadingness Index (HMMI).

This space stores the experiment materials, R code, PRE/POST results, test structures, and Human Multimodal Misleadingness Index (HMMI) calculations.

250
Test Types / Видів тестів
3
Modes / Режими: Graphical, Textual, Mixed
R
Analytics Code / Код аналітики
1%
Free Preview / Безкоштовний перегляд
📊

Структура експерименту / Experiment structure

Експеримент Multimodal Cognitive Digital Twins охоплює графічні, текстові та змішані завдання. Тут акумулюються дані про інтерпретацію, помилки, стійкість до введення в оману, а також PRE/POST оцінювання HMMI.

The Multimodal Cognitive Digital Twins experiment includes graphical, textual, and mixed tasks. This repository stores interpretation traces, errors, resistance-to-misleading patterns, and PRE/POST HMMI evaluations.

💻

R code / Код R

У системі зберігаються R-скрипти для статистики, обчислення субіндексів, інтегрального індексу HMMI, побудови графіків та перевірки гіпотез.

The system stores R scripts for statistics, subindex calculations, integral HMMI computation, figure generation, and hypothesis testing.

🧠

PRE / POST HMMI

Платформа дозволяє порівнювати базові та підсумкові значення Human Multimodal Misleadingness Index (HMMI) до і після навчального впливу.

The platform allows comparison of baseline and post-intervention Human Multimodal Misleadingness Index (HMMI) values.

🔗

Базова платформа / Open platform

Усі матеріали пов’язані з відкритою базовою платформою: https://gpt.iis.org.ua/

All materials are linked to the open base platform: https://gpt.iis.org.ua/

Доступ / Access

Безкоштовно можна ознайомитися лише з 1% інформації. Повний доступ надається за запитом після публікації статті “Multimodal Cognitive Digital Twins: Modeling the Impact of Misleading Charts and Texts in School-Based Learning”.

Only 1% of the information is available for free preview. Full access is provided upon request after publication of the article “Multimodal Cognitive Digital Twins: Modeling the Impact of Misleading Charts and Texts in School-Based Learning”.

Відеолекція TEDx

2 Videos

Технічні вимоги до VR-навчання

Для ефективного використання віртуальної реальності (VR) у навчальному процесі необхідно враховувати такі технічні аспекти:


1. Обладнання

VR-гарнітура

🔹 Типи пристроїв:

  • Автономні гарнітури (Meta Quest 2/3, HTC Vive Focus) – не потребують комп’ютера, але мають обмежену продуктивність.
  • Провідні гарнітури (HTC Vive Pro, Valve Index, Meta Quest Pro (з підключенням до ПК)) – підключаються до ПК, забезпечують кращу графіку та продуктивність.
  • Мобільні VR-рішення (Google Cardboard, Samsung Gear VR) – бюджетний варіант, працює зі смартфонами.

🔹 Мінімальні технічні характеристики:

  • Роздільна здатність екрана: 1920×1080 на кожне око (або вище).
  • Частота оновлення: 90 Гц і вище (для плавного відтворення).
  • Поле зору: від 100° (краще 110°+ для реалістичного ефекту).
  • Сенсори відстеження: 6DoF (шестиступеневе відстеження) для повноцінного занурення.

Комп’ютер для VR (для гарнітур із підключенням до ПК)

🔹 Мінімальні вимоги:

  • Процесор: Intel Core i5-10600K / AMD Ryzen 5 3600 або кращий.
  • Оперативна пам’ять: 16 ГБ RAM.
  • Відеокарта: NVIDIA GTX 1660 Ti / RTX 3060 / AMD RX 6600 XT або вище.
  • Порти: USB 3.0, DisplayPort 1.4 або HDMI 2.0.
  • ОС: Windows 10/11 (64-bit).

🔹 Рекомендовані вимоги (для комфортного навчання у VR):

  • Процесор: Intel Core i7-12700K / AMD Ryzen 7 5800X.
  • Оперативна пам’ять: 32 ГБ RAM.
  • Відеокарта: NVIDIA RTX 3080 / 4080 або AMD RX 6800 XT.
  • SSD-диск: мінімум 512 ГБ (VR-програми займають багато місця).

Додаткові аксесуари

  • Контролери VR для взаємодії (залежно від гарнітури).
  • Трекінгові сенсори (якщо гарнітура потребує).
  • Високошвидкісний інтернет для онлайн-курсів та оновлень (мін. 50 Мбіт/с).

2. Програмне забезпечення

Операційна система

  • Windows 10/11 (для більшості провідних VR-рішень).
  • Android (для автономних гарнітур, таких як Meta Quest).
  • macOS (обмежена підтримка, в основному для WebVR).

VR-движки та платформи

  • Unreal Engine 5 (для реалістичних VR-сцен).
  • Unity 3D (для створення навчальних VR-додатків).
  • OpenXR, SteamVR, Oculus SDK (для сумісності з різними платформами).

Навчальне програмне забезпечення

  • VR Labs – для хімічних експериментів.
  • Math VR – візуалізація математичних понять.
  • Google Tilt Brush, Gravity Sketch – для мистецтва та 3D-моделювання.
  • Google Expeditions (VR) – віртуальні екскурсії.
  • MEL Chemistry VR – вивчення молекулярної будови речовин.

3. Приміщення та безпека

Фізичний простір для VR

  • Мінімальна площа: 2×2 м (для стаціонарного VR).
  • Ідеальний простір: 3×3 м або більше (для рухомого VR).
  • Відсутність перешкод (меблі, дроти, крихкі предмети).

Комфорт та безпека

✅ Перерви кожні 20-30 хвилин для запобігання втомі.
✅ Освітлення: м’яке, без відблисків (краще затемнене приміщення).
✅ Налаштування меж безпечної зони у VR (Guardian, Chaperone).


4. Інтернет та зберігання даних

  • Швидкість підключення: Мінімум 50 Мбіт/с для завантаження VR-контенту.
  • Хмарне сховище: Google Drive, Dropbox, або власний сервер для навчальних матеріалів.
  • Захист даних: SSL-шифрування, двофакторна автентифікація для збереження конфіденційності.

5. Інтеграція з освітньою платформою

  • Сумісність із Moodle, Google Classroom, Microsoft Teams.
  • Підтримка VR-аватарів для дистанційного навчання.
  • Можливість створення VR-квестів, тестів і симуляцій.

Висновок

Щоб VR-навчання було ефективним, потрібна якісна гарнітура, потужний комп’ютер (або автономний пристрій), просторе приміщення та спеціалізоване програмне забезпечення. VR відкриває нові можливості для освіти, але вимагає відповідної технічної бази та організації. 🚀

Мрія починає використовувати віртуальну реальність (VR-2, 3, 4 D) у навчанні. Це допомагає зробити складні теми більш наочними та захопливими. Ось деякі теми з математики, хімії та мистецтва, які варто вивчати через VR, а також рекомендації щодо віку.

1. Математика

VR допомагає візуалізувати абстрактні математичні поняття та робить навчання інтерактивним.

📌 Теми для вивчення:

  • Геометрія та просторове мислення (об’ємні фігури, перетини, симетрія) – 7+ років
  • Тригонометрія (візуалізація синуса, косинуса, хвиль) – 12+ років
  • Графіки функцій (просторові зображення парабол, гіпербол, експонент) – 12+ років
  • Фрактали та їх застосування – 10+ років
  • Статистика та ймовірність (візуалізація даних, робота з графіками) – 14+ років

🔹 Користь VR: покращує розуміння абстрактних понять, допомагає відчути математичні структури у просторі.

2. Хімія

У хімії VR дозволяє “зануритися” у мікросвіт молекул, хімічних реакцій та структури речовин.

📌 Теми для вивчення:

  • Будова атома та періодична таблиця – 10+ років
  • Молекулярні структури та хімічні зв’язки – 12+ років
  • Хімічні реакції в 3D (спостереження реакцій на молекулярному рівні) – 12+ років
  • Органічна хімія та біохімія (будова білків, ДНК, ферментів) – 14+ років
  • Лабораторні експерименти у VR (безпечне моделювання реакцій) – 14+ років

🔹 Користь VR: безпечний експериментальний досвід, глибше розуміння процесів, яких неможливо побачити очима.

3. Мистецтво

VR у мистецтві допомагає взаємодіяти з картинами, скульптурами, архітектурними об’єктами та навіть створювати власні твори.

📌 Теми для вивчення:

  • Історія мистецтва (занурення у музеї, розгляд творів у 3D) – 7+ років
  • Техніки живопису та скульптури (імітація мазків пензля, ліплення) – 10+ років
  • Архітектура та дизайн (створення 3D-моделей будівель) – 12+ років
  • Графічний та цифровий арт у VR (малювання в тривимірному просторі) – 12+ років
  • Реставрація картин та аналіз композиції – 14+ років

🔹 Користь VR: занурення в епохи мистецтва, експериментування з творчістю без обмежень.

З якого віку?

✅ 7-10 років (до 5 хв) – базові теми (геометрія, історія мистецтва, будова атома).
✅ 10-14 років (до 10 хв) – більш складні концепції (тригонометрія, молекулярна хімія, цифрове мистецтво).
✅ 14+ років (20 хв) – поглиблене навчання (органічна хімія, статистика, архітектурне моделювання).

VR – це потужний інструмент для інтерактивного навчання, який допомагає зробити освіту більш ефективною та захопливою.
РЕЄСТРУЙТЕСЯ НА НАВЧАННЯ ЧЕРЕЗ ВАЙБЕР 0675072955🚀

Схожі записи