Back to Article
Analyses
Download Source

Analyses

Author

Isaac T. Petersen, Zachary Demko, and Megan Schumer

Published

August 26, 2026

In [1]:
Code
#install.packages("remotes")
#remotes::install_github("DevPsyLab/petersenlab")

Intro

Preamble

Install Libraries

Load Libraries

In [2]:
Code

library("petersenlab") #located here: https://github.com/DevPsyLab/petersenlab
library("knitr")
library("magick")
Linking to ImageMagick 6.9.12.98
Enabled features: fontconfig, freetype, fftw, heic, lcms, pango, raw, webp, x11
Disabled features: cairo, ghostscript, rsvg
Using 4 threads
Code

library("grid")
library("patchwork")
library("tidyverse")
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.2.1     ✔ readr     2.2.0
✔ forcats   1.0.1     ✔ stringr   1.6.0
✔ ggplot2   4.0.3     ✔ tibble    3.3.1
✔ lubridate 1.9.5     ✔ tidyr     1.3.2
✔ purrr     1.2.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Load Data

In [3]:
Code
longitudinalStudies <- read_csv("../Data/longitudinalStudies.csv") #read_csv("./Data/longitudinalStudies.csv")
Rows: 46 Columns: 17
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (6): study, studyLabel, designType, sampleType, country, continent
dbl (8): sampleSize, yearStart, yearMostRecentAssessment, yearEnd, ageStartM...
lgl (3): prenatalRecruitment, active, interventionPrevention

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Code
longitudinalExternalizingStudies <- read_csv("../Data/longitudinalExternalizingStudies.csv") #read_csv("./Data/longitudinalExternalizingStudies.csv")
Rows: 20 Columns: 22
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (14): sample, sampleLabel, study, year, studyLabel, measurementOccasions...
dbl  (6): sampleSize, ageStartMin, ageStartMax, ageEndMin, ageEndMax, maxTim...
lgl  (2): registry, developmentalScaling

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
Code
externalizingFacets <- read_csv("../Data/externalizingFacets.csv") #read_csv("./Data/externalizingFacets.csv")
Rows: 30 Columns: 4
── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (4): facet, facetLabel, facetDefinition, positiveOpposite

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Plots

Cognitive Trajectories

In [4]:
Code

# 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)
  )
Different Cognitive Trajectories of Aging
Different Cognitive Trajectories of Aging

Externalizing Trajectories

In [5]:
Code

# 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)
  )
Externalizing behavior across development
Externalizing Behavior Across Development

Longitudinal Studies

In [6]:
Code
# 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)
  )
In [7]:
Code

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
(Approximate) Ages Spanned by Various Lengthy Longitudinal Studies
(Approximate) Ages Spanned by Various Lengthy Longitudinal Studies

Longitudinal Externalizing Studies

In [8]:
Code
# 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"
    )
  )
In [9]:
Code

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
(Approximate) Ages Spanned by Externalizing Trajectories in Various Lengthy Longitudinal Studies Examining Individuals' Trajectories of Externalizing Behavior
(Approximate) Ages Spanned by Externalizing Trajectories in Various Lengthy Longitudinal Studies Examining Individuals’ Trajectories of Externalizing Behavior

Tables

Externalizing Facets

In [10]:
Code

knitr::kable(
  externalizingFacets %>% select(facetLabel, facetDefinition, positiveOpposite),
  col.names = c("Facet","Definition","Potential Positive Opposite")
)
In [11]:
Externalizing Facets Identified in Content Analysis of Externalizing Measures.
Facet Definition Potential Positive Opposite
Apathy/Indolence/Disengagement Unconcerned about achievement, low motivation, low concern about how one’s abilities or actions are evaluated, specific to contexts in which others have expectations for performance (e.g., school and work), specifically low effort rather than performance Diligence/Achievement motivation
Attention seeking/Exhibitionism Exaggerated or dramatic expressions, interrupting others, inappropriate or provocative behaviors, provoking reactions Humility/Appropriate self-expression
Behavioral addiction Impulsive/compulsive engagement in rewarding non-substance behaviors (e.g., gambling, video games, risky sex, pornography, food, the internet, mobile devices, shopping) Self-regulated engagement
Blame externalization Attribute cause of problems or failures to external factors, falsely claiming victimhood, blaming others Personal responsibility/Accountability
Boredom proneness Expressing boredom often, difficulty maintaining interest, lack of engagement Curiosity/Sustained engagement
Callous aggression Inflicting harm without feeling remorse or concern, usually proactive/intentional Compassionate protection/Benevolence
Callousness/Disregard for others/Selfishness/Egocentricity Emotional detachment, indifference to well-being of others Empathy/Compassion/Concern for others/Helping others/Sharing
Deceitfulness/Fraud/Lying/Cheating/Dishonesty/Sneakiness/Exploitation Keeping the truth hidden, especially to get an advantage (e.g., lying, withholding information, manipulation, making false promises) Honesty/Integrity/Fairness
Deviant peer affiliation Affiliating with peers who engage in deviant or delinquent behaviors Prosocial peer affiliations
Destructive aggression/Destruction of property Destruction of property, self, or others, objects Constructiveness/Care for property
Distractibility/Inattention/Attention dysregulation/Forgetfulness/Daydreaming Difficulty maintaining focus, attention, or concentration, frequent attention shifts Attentional control/Sustained attention
Domineering/Bossiness Asserting control, power, and authority in an overbearing or oppressive manner Collaborativeness
Excitement seeking/Risk taking/Sensation seeking Tendency to impulsively pursue new and different sensations, especially ones that are intense, exhilarating, thrilling, unsafe, etc. (e.g., risk taking, preference for novelty, intensity) Prudent exploration/Measured novelty seeking
Grandiosity/Overconfidence Exaggerated sense of self-importance, sense of superiority or specialness Realistic self-confidence
Hostility/Rudeness Hostile behavior, unfriendliness, resentment, antagonism, ranging from mild irritation to intense rage, interpret others’ behavior as hostile Warmth/Friendliness/Kindness
Hyperactivity High levels of physical activity, restlessness, difficulty engaging in quiet activities Behavioral regulation
Impulsivity/Disinhibition/Impatient urgency Tendency to act without thinking, disinhibited engagement Planful control
Irresponsibility/Unreliability/Disorganization Failing to meet obligations, avoiding addressing difficulties, inconsistency, lack of organization and planning Responsibility/Conscientiousness/Dependability/Reliability/Organization
Manipulativeness/Psychological aggression Tendency to influence or control others to achieve one’s own goals or desires, e.g., playing the victim, flattery, gaslighting, guilt-tripping, psychological aggression Sincerity/Authenticity
Mistrust/Suspiciousness/Paranoia Lack of confidence in the reliability, intentions of others, difficulty forming close relationships with others, difficulty forgiving Interpersonal trust (appropriately calibrated)
Oppositionality/Stubbornness Persistent and defiant attitude, tendency to challenge authority, refusal to comply, argumentativeness (could include while complying), etc. Cooperativeness
Physical aggression Use of physical force or violence to harm others or their property Respect for others’ bodies/Helping others
Punishment insensitivity Does not change behavior after punishment, high tolerance for negative outcomes Responsive to consequences
Rebelliousness/Rule-breaking/Noncompliance Doing things differently than one is asked to do (e.g., breaking house rules) Compliance/Civic responsibility
Relational aggression Aggression intended to harm others through deliberate manipulation of their social standing and relationships (e.g., exclusion, speaking negatively of another, etc.) Inclusion
Sexual aggression Engaging in sexual activity with someone who does not or cannot consent to that behavior, or threatening to do so (e.g., harassment) Respect for consent
Impulsive sexual behavior/Risky sexual behavior Engaging in risky sexual activity (e.g., sex without contraceptives) Responsible sexual decision-making
(Harmful) Substance Use/Problems Harmful use of any drugs (e.g., alcohol, tobacco, illegal drugs) Healthy choices around substance use
Theft/Stealing Unauthorized taking of someone else’s property without their knowledge or consent Respect for people’s possessions
Verbal Aggression Communication with an intention to harm an individual through words, tone, or manner Respectful communication

Session Info

In [12]:
Code
sessionInfo()
R version 4.6.1 (2026-06-24)
Platform: x86_64-pc-linux-gnu
Running under: Ubuntu 24.04.4 LTS

Matrix products: default
BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3 
LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0

locale:
 [1] LC_CTYPE=C.UTF-8       LC_NUMERIC=C           LC_TIME=C.UTF-8       
 [4] LC_COLLATE=C.UTF-8     LC_MONETARY=C.UTF-8    LC_MESSAGES=C.UTF-8   
 [7] LC_PAPER=C.UTF-8       LC_NAME=C              LC_ADDRESS=C          
[10] LC_TELEPHONE=C         LC_MEASUREMENT=C.UTF-8 LC_IDENTIFICATION=C   

time zone: UTC
tzcode source: system (glibc)

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods  
[8] base     

other attached packages:
 [1] lubridate_1.9.5   forcats_1.0.1     stringr_1.6.0     dplyr_1.2.1      
 [5] purrr_1.2.2       readr_2.2.0       tidyr_1.3.2       tibble_3.3.1     
 [9] ggplot2_4.0.3     tidyverse_2.0.0   patchwork_1.3.2   magick_2.9.1     
[13] knitr_1.51        petersenlab_1.2.3

loaded via a namespace (and not attached):
 [1] tidyselect_1.2.1    psych_2.6.5         viridisLite_0.4.3  
 [4] farver_2.1.2        S7_0.2.2            fastmap_1.2.0      
 [7] digest_0.6.39       rpart_4.1.27        timechange_0.4.0   
[10] lifecycle_1.0.5     cluster_2.1.8.2     magrittr_2.0.5     
[13] compiler_4.6.1      rlang_1.3.0         Hmisc_5.2-6        
[16] tools_4.6.1         yaml_2.3.12         data.table_1.18.6.1
[19] labeling_0.4.3      htmlwidgets_1.6.4   bit_4.6.0          
[22] mnormt_2.1.2        plyr_1.8.9          RColorBrewer_1.1-3 
[25] foreign_0.8-91      withr_3.0.3         nnet_7.3-20        
[28] stats4_4.6.1        lavaan_0.7-2        xtable_1.8-8       
[31] colorspace_2.1-3    scales_1.4.0        MASS_7.3-65        
[34] cli_3.6.6           mvtnorm_1.4-2       crayon_1.5.3       
[37] rmarkdown_2.31      reformulas_0.4.4    generics_0.1.4     
[40] otel_0.2.0          rstudioapi_0.19.0   tzdb_0.5.0         
[43] reshape2_1.4.5      minqa_1.2.8         DBI_1.3.0          
[46] splines_4.6.1       parallel_4.6.1      base64enc_0.1-6    
[49] mitools_2.4         vctrs_0.7.3         boot_1.3-32        
[52] Matrix_1.7-5        jsonlite_2.0.0      hms_1.1.4          
[55] bit64_4.8.4         Formula_1.2-6       htmlTable_2.5.0    
[58] glue_1.8.1          nloptr_2.2.1        stringi_1.8.9      
[61] gtable_0.3.6        quadprog_1.5-8      lme4_2.0-6         
[64] pillar_1.11.1       htmltools_0.5.9     R6_2.6.1           
[67] Rdpack_2.6.6        mix_1.0-13          vroom_1.7.1        
[70] evaluate_1.0.5      pbivnorm_0.6.0      lattice_0.22-9     
[73] rbibutils_2.4.1     backports_1.5.1     Rcpp_1.1.2         
[76] gridExtra_2.3.1     nlme_3.1-169        checkmate_2.3.4    
[79] xfun_0.60           pkgconfig_2.0.3    

Rstudio Version

In [13]:
Code
#rstudioapi::versionInfo()