---
title: "Analyses"
author: "Isaac T. Petersen, Zachary Demko, and Megan Schumer"
date: '`r format(Sys.Date(), "%B %d, %Y")`'
format:
  html:
    toc: true
    toc-depth: 4
    number-sections: true
    number-depth: 4
    code-fold: show
    echo: true
    error: true
    embed-resources: true
    self-contained-math: true
---

```{r}
#install.packages("remotes")
#remotes::install_github("DevPsyLab/petersenlab")
```

# Intro

# Preamble

## Install Libraries

<!-- *IMPORTANT NOTE*: Because of how pandoc works, the figure and table labels must be all lowercase for cross-references to work -->

## Load Libraries

```{r}
#| message: false
#| warning: false

library("petersenlab") #located here: https://github.com/DevPsyLab/petersenlab
library("knitr")
library("magick")
library("grid")
library("patchwork")
library("tidyverse")
```

## Load Data

```{r}
longitudinalStudies <- read_csv("../Data/longitudinalStudies.csv") #read_csv("./Data/longitudinalStudies.csv")

longitudinalExternalizingStudies <- read_csv("../Data/longitudinalExternalizingStudies.csv") #read_csv("./Data/longitudinalExternalizingStudies.csv")

externalizingFacets <- read_csv("../Data/externalizingFacets.csv") #read_csv("./Data/externalizingFacets.csv")
```

# Plots

## Cognitive Trajectories

```{r}
#| label: fig-lifespancognitivetrajectories
#| fig-cap: "Different Cognitive Trajectories of Aging"
#| fig-alt: "Different Cognitive Trajectories of Aging"
#| apa-note: "**Panel A**: Hypothetical models for different cognitive trajectories of aging. MCI = mild cognitive impairment. (Figure in Panel A reprinted from @Borelli2018, Figure 1, p. 222. Borelli, W. V., Carmona, K. C., Studart-Neto, A., Nitrini, R., Caramelli, P., & Costa, J. C. d. (2018). Operationalized definition of older adults with high cognitive performance. *Dementia & Neuropsychologia*, *12*(3), 221–227. <https://doi.org/10.1590/1980-57642018dn12-030001>). **Panel B**: Theoretical illustration of inter-individual variability in cognitive aging trajectories. Each gray line represents one individual hypothetical cognitive health trajectory. The orange line marks the threshold for functional independence; once an individual's cognitive health drops below this level, autonomous daily living is compromised. (Figure in Panel B reprinted from @Abrous2026, Figure 1, p. 2. Abrous, D. N., Blin, N., Boraxbekk, C.-J., Catheline, G., Fitzsimons, C. P., Hilscher, M., Lemoine, M., Lopes, L. V., Maass, A., Nilsson, M., Nyberg, L., Rasmussen, L. J., Remondes, M., Sauvage, M., Schreiber, S., & Wolbers, T. (2026). Hallmarks of healthy cognitive aging: Inter-individual differences in aging trajectories. *Ageing Research Reviews*, *119*, 103102. <https://doi.org/10.1016/j.arr.2026.103102>)."
#| fig-width: 12
#| fig-height: 5
#| fig-dpi: 300

# Read images
lifespanCognitiveTrajectoriesFigA <- magick::image_read("../Figures/Borelli2018_figure1.jpg") #magick::image_read("./Figures/Borelli2018_figure1.jpg")
lifespanCognitiveTrajectoriesFigB <- magick::image_read("../Figures/Abrous2026_figure1.jpg") #magick::image_read("./Figures/Abrous2026_figure1.jpg")

# Convert images to patchwork-compatible objects
lifespanCognitiveTrajectoriesPanelA <- patchwork::wrap_elements(
  panel = grid::rasterGrob(as.raster(lifespanCognitiveTrajectoriesFigA), interpolate = TRUE)
) +
  labs(tag = "A")

lifespanCognitiveTrajectoriesPanelB <- patchwork::wrap_elements(
  panel = grid::rasterGrob(as.raster(lifespanCognitiveTrajectoriesFigB), interpolate = TRUE)
) +
  labs(tag = "B")

# Combine panels
lifespanCognitiveTrajectoriesPanelA + lifespanCognitiveTrajectoriesPanelB +
  patchwork::plot_layout(widths = c(53, 47)) &
  theme(
    plot.tag = element_text(face = "bold", size = 14),
    plot.margin = margin(0, 0, 0, 0)
  )
```

## Externalizing Trajectories

```{r}
#| label: fig-externalizing-by-age
#| fig-cap: "Externalizing Behavior Across Development"
#| fig-alt: "Externalizing behavior across development"
#| apa-note: "**Panel A**: The age-crime participation curve from age 9 through 64 in cohort members registered for antisocial and/or criminal behavior in a birth cohort recruited in Stockholm, Sweden (*N* = 4,825), based on official crime records. The steep peak in crime rate in the adolescent years is similar to the age-crime curve in the United States; however, the steepness of the age-crime curve differs within country across birth cohorts [@Steffensmeier2025]. (Figure adapted from @Sivertsson2024, Figure 1, p. 7. Sivertsson, F., Carlsson, C., Almquist, Y. B., & Brännström, L. (2024). Offending trajectories from childhood to retirement age: Findings from the Stockholm birth cohort study. *Journal of Criminal Justice*, *91*, 102155. <https://doi.org/10.1016/j.jcrimjus.2024.102155>). **Panel B**: A stylized depiction of Moffitt's [-@Moffitt1993] developmental taxonomy of externalizing behavior, adapted to include a childhood limited subgroup. **Panel C**: Individuals' (*N* = 585) longitudinal trajectories of externalizing problems from childhood to adulthood based on annual assessments of mother-, father-, teacher-, peer-, and self-report (at relevant ages). Average trajectory in red. (Figure adapted from @Petersen2015, Figure 2, Petersen, I. T., Bates, J. E., Dodge, K. A., Lansford, J. E., & Pettit, G. S. (2015). Describing and predicting developmental profiles of externalizing problems from childhood to adulthood. *Development and Psychopathology*, *27*(3), 791–818. <https://doi.org/10.1017/S0954579414000789>)."
#| fig-width: 12
#| fig-height: 8
#| fig-dpi: 300

# Read images
externalizingByAgeFigA <- magick::image_read("../Figures/Sivertsson2024_figure1.png") #magick::image_read("./Figures/Sivertsson2024_figure1.png")
externalizingByAgeFigB <- magick::image_read("../Figures/developmentalTaxonomy.png") #magick::image_read("./Figures/developmentalTaxonomy.png")
externalizingByAgeFigC <- magick::image_read("../Figures/Petersen2015_adapted.png") #magick::image_read("./Figures/Petersen2015_adapted.png")

# Convert images to patchwork-compatible objects
externalizingByAgePanelA <- patchwork::wrap_elements(
  panel = grid::rasterGrob(as.raster(externalizingByAgeFigA), interpolate = TRUE)
) +
  labs(tag = "A")

externalizingByAgePanelB <- patchwork::wrap_elements(
  panel = grid::rasterGrob(as.raster(externalizingByAgeFigB), interpolate = TRUE)
) +
  labs(tag = "B")

externalizingByAgePanelC <- patchwork::wrap_elements(
  panel = grid::rasterGrob(as.raster(externalizingByAgeFigC), interpolate = TRUE)
) +
  labs(tag = "C")

# Combine panels
externalizingByAgePanelA /
(externalizingByAgePanelB + externalizingByAgePanelC) +
  patchwork::plot_layout(
    heights = c(1, 1)
  ) &
  theme(
    plot.tag = element_text(face = "bold", size = 14),
    plot.margin = margin(0, 0, 0, 0)
  )
```

## Longitudinal Studies

```{r}
# prepare data for plot
longitudinalStudies_plotData <- bind_rows(

  # ---- start cross-section ----
  longitudinalStudies %>%
    mutate(
      segment_group = "cross-section",
      segment_type = "start_crossSection",
      ageStart = ageStartMin,
      ageEnd = ageStartMax
    ) %>%
    select(study, studyLabel, ageStart, ageEnd, segment_group, segment_type),

  # ---- core (ONLY if true longitudinal cohort span exists) ----
  longitudinalStudies %>%
    mutate(has_cor = ageStartMax < ageEndMin) %>%
    filter(has_cor) %>%
    mutate(
      segment_group = "core",
      segment_type = "core",
      ageStart = ageStartMax,
      ageEnd = ageEndMin
    ) %>%
    select(study, studyLabel, ageStart, ageEnd, segment_group, segment_type),

  # ---- end cross-section ----
  longitudinalStudies %>%
    mutate(
      segment_group = "cross-section",
      segment_type = "end_crossSection",
      ageStart = ageEndMin,
      ageEnd = ageEndMax
    ) %>%
    select(study, studyLabel, ageStart, ageEnd, segment_group, segment_type)
)

# Merge active status
longitudinalStudies_plotData <- longitudinalStudies_plotData %>%
  left_join(
    longitudinalStudies %>% select(study, active),
    by = c("study")
  )

# Order studies for plot
study_order <- longitudinalStudies %>%
  arrange(ageEndMax, ageStartMin) %>%
  pull(studyLabel)

longitudinalStudies_plotData <- longitudinalStudies_plotData %>%
  mutate(studyLabelFactor = factor(studyLabel, levels = study_order))

# Prenatal enrollment
prenatal_df <- longitudinalStudies %>%
  filter(prenatalRecruitment == TRUE) %>%
  mutate(
    age = 0,
    studyLabelFactor = factor(studyLabel, levels = study_order)
  )
```

```{r}
#| label: fig-longitudinalstudies
#| fig-cap: "(Approximate) Ages Spanned by Various Lengthy Longitudinal Studies"
#| fig-alt: "(Approximate) Ages Spanned by Various Lengthy Longitudinal Studies"
#| apa-note: "The list of longitudinal studies is as of this writing and is not exhaustive. Studies that are no longer active are shown in gray. Solid lines reflect fully longitudinal spans (i.e., the same individuals were followed over time). Dotted lines reflect ages assessed cross-sectionally—even if some participants may have been followed longitudinally. For instance, if a study recruited 5–10-year-old children and followed each child for 20 years, the study would have dotted lines from ages 5–10 and from ages 25–30. Studies shown entirely with dotted lines assessed their full age range cross-sectionally but still included longitudinal follow-up of some participants. A star at age 0 represents that participants were enrolled before birth and the study included prenatal assessments. Ages spanned reflect ages when assessments were collected directly from participants; ages spanned do not include links to registry data (e.g., birth records, offending records). Age was truncated at 100; thus, age 100 indicates that participants were followed into their 90s (or until death)."
#| fig-height: 8

plot_longitudinalStudies <- ggplot2::ggplot(
  data = longitudinalStudies_plotData,
  mapping = aes(
    y = studyLabelFactor
  )
) +
  geom_segment(
    aes(
      x = ageStart,
      xend = ageEnd,
      yend = studyLabelFactor,
      linetype = segment_group,
      color = active
    ),
    linewidth = 1
  ) +
  scale_linetype_manual(
    values = c(
      "cross-section" = "11",
      "core" = "solid"
    ),
    guide = "none"
  ) +
  scale_color_manual(
    values = c(
      "TRUE" = "black",
      "FALSE" = "gray70"
    ),
    guide = "none"
  ) +
  geom_point(
    data = prenatal_df,
    aes(
      x = age,
      y = studyLabelFactor,
      color = active
    ),
    shape = 8,
    size = 3
  ) +
  labs(
    x = "Age (years)",
    y = NULL
  ) +
  theme_classic()

plot_longitudinalStudies
```

## Longitudinal Externalizing Studies

```{r}
# Prepare plot data
longitudinalExternalizingStudies_plotData <- bind_rows(

  # start cross-sectional span
  longitudinalExternalizingStudies %>%
    mutate(
      segment_group = "cross-section",
      ageStart = ageStartMin,
      ageEnd = ageStartMax
    ) %>%
    select(
      sample,
      sampleLabel,
      study,
      studyLabel,
      ageStart,
      ageEnd,
      segment_group
    ),

  # core longitudinal span
  longitudinalExternalizingStudies %>%
    mutate(has_core = ageStartMax < ageEndMin) %>%
    filter(has_core) %>%
    mutate(
      segment_group = "core",
      ageStart = ageStartMax,
      ageEnd = ageEndMin
    ) %>%
    select(
      sample,
      sampleLabel,
      study,
      studyLabel,
      ageStart,
      ageEnd,
      segment_group
    ),

  # end cross-sectional span
  longitudinalExternalizingStudies %>%
    mutate(
      segment_group = "cross-section",
      ageStart = ageEndMin,
      ageEnd = ageEndMax
    ) %>%
    select(
      sample,
      sampleLabel,
      study,
      studyLabel,
      ageStart,
      ageEnd,
      segment_group
    )
)

# Merge registry/developmental scaling info
longitudinalExternalizingStudies_plotData <- longitudinalExternalizingStudies_plotData %>%
  left_join(
    longitudinalExternalizingStudies %>%
      select(study, registry, developmentalScaling),
    by = "study"
  ) %>%
  mutate(
    plotColor = case_when(
      developmentalScaling ~ "developmentalScaling",
      registry ~ "registry",
      TRUE ~ "standard"
    )
  )

# Study ordering
longitudinalExternalizingStudies_order <- longitudinalExternalizingStudies %>%
  arrange(ageEndMax, ageStartMin) %>%
  pull(studyLabel)

# Add numeric study positions
study_positions <- tibble(
  studyLabel = longitudinalExternalizingStudies_order,
  study_num = seq_along(longitudinalExternalizingStudies_order)
)

# Main plotting data
longitudinalExternalizingStudies_plotData <- longitudinalExternalizingStudies_plotData %>%
  left_join(study_positions, by = "studyLabel") %>%
  mutate(
    line_y = study_num + 0.25
  )

# Measurement occasions

longitudinalExternalizingStudies_measurementOccasions <- longitudinalExternalizingStudies %>%
  filter(!is.na(measurementOccasions)) %>%
  separate_rows(
    measurementOccasions,
    sep = ";"
  ) %>%
  mutate(
    measurementOccasions = as.numeric(str_trim(measurementOccasions))
  ) %>%
  left_join(study_positions, by = "studyLabel") %>%
  mutate(
    point_y = study_num + 0.45,
    plotColor = case_when(
      developmentalScaling ~ "developmentalScaling",
      registry ~ "registry",
      TRUE ~ "standard"
    )
  )

# Sample labels
longitudinalExternalizingStudies_sampleLabels <- longitudinalExternalizingStudies %>%
  left_join(study_positions, by = "studyLabel") %>%
  mutate(
    label_x = ageStartMin,
    label_y = study_num,
    plotColor = case_when(
      developmentalScaling ~ "developmentalScaling",
      registry ~ "registry",
      TRUE ~ "standard"
    )
  )
```

```{r}
#| label: fig-longitudinal-externalizing-studies
#| fig-cap: "(Approximate) Ages Spanned by Externalizing Trajectories in Various Lengthy Longitudinal Studies Examining Individuals' Trajectories of Externalizing Behavior"
#| fig-alt: "(Approximate) Ages Spanned by Externalizing Trajectories in Various Lengthy Longitudinal Studies Examining Individuals' Trajectories of Externalizing Behavior"
#| apa-note: "The list of longitudinal studies is not exhaustive. Studies that are based on registry data are shown in gray. Studies that used developmental scaling to harmonize scores across ages (i.e., to link scores across ages onto the same scale) are in green. Measurement occasions are depicted with solid circles. Note that, in some studies, measurement occasions only apply to a subset of participants in that study—in some cases, no participant was assessed at all measurement occasions. Solid lines reflect fully longitudinal spans (i.e., the same individuals were followed over time). Dotted lines reflect ages assessed cross-sectionally—even if some participants may have been followed longitudinally. For instance, if a study recruited 5–10-year-old children and followed each child for 20 years, the study would have dotted lines from ages 5–10 and from ages 25–30. Studies shown entirely with dotted lines assessed their full age range cross-sectionally but still included longitudinal follow-up of participants. 'MTSFGCLS' = Montreal Two Samples Four Generations Cross-sectional and Longitudinal Studies."
#| fig-height: 8

plot_longitudinalExternalizingStudies <- ggplot2::ggplot() +
  geom_segment(
    data = longitudinalExternalizingStudies_plotData,
    aes(
      x = ageStart,
      xend = ageEnd,
      y = line_y,
      yend = line_y,
      linetype = segment_group,
      color = plotColor
    ),
    linewidth = 1
  ) +
  geom_point(
    data = longitudinalExternalizingStudies_measurementOccasions,
    aes(
      x = measurementOccasions,
      y = point_y,
      color = plotColor
    ),
    size = 1.5
  ) +
  geom_text(
    data = longitudinalExternalizingStudies_sampleLabels,
    aes(
      x = label_x,
      y = label_y,
      label = sampleLabel,
      color = plotColor
    ),
    hjust = 0,
    vjust = 0.5,
    size = 2.8
  ) +
  scale_y_continuous(
    breaks = study_positions$study_num,
    labels = study_positions$studyLabel
  ) +
  scale_linetype_manual(
    values = c(
      "cross-section" = "11",
      "core" = "solid"
    ),
    guide = "none"
  ) +
  scale_color_manual(
    values = c(
      standard = "black",
      registry = "gray70",
      developmentalScaling = "#2E7D32"
    ),
    guide = "none"
  ) +
  coord_cartesian(
    clip = "off"
  ) +
  labs(
    x = "Age (years)",
    y = NULL
  ) +
  theme_classic()

plot_longitudinalExternalizingStudies
```

# Tables

## Externalizing Facets

```{r}
#| label: tbl-externalizingfacets
#| tbl-cap: "Externalizing Facets Identified in Content Analysis of Externalizing Measures."
#| apa-note: "Transdiagnostic facets of psychopathology, which encompass externalizing problems, include irritability/reactive anger, unemotionality, sleep problems, social problems, learning problems, and low functional independence."
#| apa-longtable: true

knitr::kable(
  externalizingFacets %>% select(facetLabel, facetDefinition, positiveOpposite),
  col.names = c("Facet","Definition","Potential Positive Opposite")
)
```

# Session Info

```{r}
sessionInfo()
```

## Rstudio Version

```{r}
#rstudioapi::versionInfo()
```
