OSCR

Cortical thickness changes precede high levels of amyloid by at least 7 years.

Code ↔ Paper

6 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 6 matches
  1. [1] § Methods › Participants ↔ scripts/01-prepSlopesYearsBeforeAB_simulated.r, lines 354–440 · score 0.70 · combined MRI, ageing MRI, MRI scans, PET scan, ADNI, BACS
  2. [2] § Results › Additional analyses ↔ scripts/10-rankThicknessChange.r, lines 672–712 · score 0.62 · CIs excluded zero, thickness changes, confidence, rank, derivative, interval
  3. [3] § Methods › Statistical analysis ↔ scripts/10-rankThicknessChange.r, lines 672–712 · score 0.57 · excluded zero, thickness changes, rank, gratia, derivative, CI
  4. [4] § Methods › Statistical analysis ↔ scripts/08-rankAmyloidOrder.r, lines 363–409 · score 0.53 · linear mixed models, tracer, regional, amyloid, SUVR, ADNI
  5. [5] § Methods › Statistical analysis ↔ scripts/10-rankThicknessChange.r, lines 400–463 · score 0.51 · GAMM interaction, thickness change, ICV, smooth, strength, trajectories
  6. [6] § Methods › Statistical analysis ↔ scripts/08-rankAmyloidOrder.r, lines 363–409 · score 0.51 · linear mixed models, tracer, rank, regional, SUVRs, intercept

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

R · 1,114 lines · 39 KB · MIT · 3 matches

  1. #========================================================================================#
  2. # Author: James M Roe, Ph.D.
  3. # Center for Lifespan Changes in Brain and Cognition, University of Oslo
  4. #
  5. # Purpose: Compute the rank order of thickness changes across all converter MRIs and correlate with the rank order of regional Aβ deposition.
  6. # Uses linear time-to-Aβ trajectories or SILA input, and computes time-to-Aβ thickness trajectories in regions of high-v-low Aβ.
  7. # Script requires individual-level data as input and is not executable
  8. #========================================================================================#
  9. #---load packages
  10. loadPackages = function() {
  11. packages = c("here", "tidyverse","magrittr","gamm4","itsadug","numDeriv","gratia","mgcv","viridis","wesanderson","asbio","broom","cowplot","data.table","stringi","tictoc","lmerTest","effects","ggpubr")
  12. new.packages = packages[!(packages %in% installed.packages()[,"Package"])]
  13. if(length(new.packages)) {
  14. install.packages(new.packages)
  15. }
  16. print(sapply(packages, require, character.only = T))
  17. print(sapply(packages, function(p) as.character(packageVersion(p))))
  18. }
  19. loadPackages()
  20. here()
  21. #---set dir
  22. b = "/cluster/projects/p274/projects/p040-ad_change/Berkeley"
  23. # b = here()
  24. setwd(b)
  25. #---set dir
  26. #---make dirstruct
  27. plotdir = "plots"; if (! dir.exists(plotdir)) { dir.create(plotdir)}
  28. resdir = "results"; if (! dir.exists(resdir)) { dir.create(resdir)}
  29. #---load data
  30. savefigs=F
  31. nTime=2
  32. agecut=30
  33. saveres=T
  34. load(file.path(b, "reproduce/data/DF_LONG_4570.Rda"))
  35. dim(DF); length(unique(DF$subject_id))
  36. # load converter/nonconverter data
  37. load(file.path(b, "reproduce/data/converters_all_negfirst_ADNINC_UPDATE.Rda"))
  38. load(file.path(b, "reproduce/data/converters_all_negfirst_BACS_UPDATE.Rda"))
  39. load(file.path(b, "reproduce/data/converters_all_negfirst_LCBC_UPDATE_REPRO_corthresh.Rda"))
  40. load(file.path(b, "reproduce/data/converters_data_for_plot_BACS_UPDATE_REPRO.Rda"))
  41. load(file.path(b, "reproduce/data/converters_data_for_plot_ADNINC_UPDATE_REPRO.Rda"))
  42. load(file.path(b, "reproduce/data/converters_data_for_plot_LCBC_UPDATE_REPRO_corthresh.Rda"))
  43. converters_allMRI_negfirst_LCBC = left_join(converters_allMRI_negfirst_LCBC,
  44. converters_allMRI_negfirst_LCBC_plotdat %>% select(imageLink, slope, intercept, age_at_threshold, contains("CL_at_thresh")) %>%
  45. rename(slope_centiloid = slope,
  46. intercept_centiloid = intercept)
  47. )
  48. converters_allMRI_negfirst_ADNINC = left_join(converters_allMRI_negfirst_ADNINC,
  49. converters_allMRI_negfirst_ADNINC_plotdat %>% select(imageLink, slope, intercept, age_at_threshold, contains("CL_at_thresh")) %>%
  50. rename(slope_centiloid = slope,
  51. intercept_centiloid = intercept)
  52. )
  53. converters_allMRI_negfirst_BACS = left_join(converters_allMRI_negfirst_BACS,
  54. converters_allMRI_negfirst_BACS_plotdat %>% select(imageLink, slope, intercept, age_at_threshold, contains("CL_at_thresh")) %>%
  55. rename(slope_centiloid = slope,
  56. intercept_centiloid = intercept)
  57. )
  58. allFeat = readLines(file.path(b, "reproduce/data/allFeatures364.txt"))
  59. adnioutlier = "029_S_0845"
  60. rois=allFeat[grepl("thickness", allFeat)]
  61. nrois=length(rois)
  62. subset.size=nrois; jj = 1
  63. N = ceiling(nrois/subset.size)
  64. print(N)
  65. start = (jj*subset.size)-subset.size+1
  66. if (jj == N) {
  67. end = nrois
  68. loopend = length(rois[start:end])
  69. } else {
  70. end = jj*subset.size
  71. loopend = subset.size
  72. }
  73. print(paste("subsetting cols", start, "-", end))
  74. rois = rois[start:end]
  75. print(rois)
  76. ROIs = rois
  77. pb = txtProgressBar(min=2, max=end, style=3)
  78. Usubs = length(unique(DF$subject_id))
  79. # load sila outputs
  80. osila_bacs = fread("/cluster/projects/p274/projects/p040-ad_change/Berkeley/scripts/SILA-AD-Biomarker/demo/output/testBACS.csv")
  81. osila_adni = fread("/cluster/projects/p274/projects/p040-ad_change/Berkeley/scripts/SILA-AD-Biomarker/demo/output/testADNINC.csv")
  82. osila_lcbc = fread("/cluster/projects/p274/projects/p040-ad_change/Berkeley/scripts/SILA-AD-Biomarker/demo/output2/testLCBC.csv")
  83. # load sila inputs (ids get changed in sila modelling)
  84. isila_all = fread("/cluster/projects/p274/projects/p040-ad_change/Berkeley/scripts/SILA-AD-Biomarker/demo/df_silo_amyloidtimeCorrect.csv")
  85. isila_adni = isila_all[isila_all$cohort == "ADNINC",] %>% rename(subject_id = subid) %>% rename(subid = subjid)
  86. isila_bacs = isila_all[isila_all$cohort == "BACS",] %>% rename(subject_id = subid) %>% rename(subid = subjid)
  87. isila_lcbc = isila_all[isila_all$cohort == "LCBC",] %>% rename(subject_id = subid) %>% rename(subid = subjid)
  88. range(osila_adni$subid)
  89. range(isila_adni$subid)
  90. range(osila_bacs$subid)
  91. range(isila_bacs$subid)
  92. range(isila_lcbc$subid)
  93. range(osila_lcbc$subid)
  94. osila_adni = left_join(osila_adni, isila_adni)
  95. osila_bacs = left_join(osila_bacs, isila_bacs)
  96. osila_lcbc = left_join(osila_lcbc, isila_lcbc)
  97. mytheme = theme(
  98. plot.background = element_rect(fill = "white"),
  99. panel.background = element_rect(fill = "white"),
  100. panel.grid.major = element_blank(),
  101. panel.grid.minor = element_blank(),
  102. title = element_text(size=17),
  103. text = element_text(color = "black", size = 18, family="Nimbus Sans Narrow"),
  104. plot.title = element_text(hjust = 0.5),
  105. # axis.ticks = element_blank(),
  106. axis.title.y = element_text(color = "black", size = 22, vjust =-1, margin = margin(0,20,0,0)),
  107. axis.title.x = element_text(color = "black", size = 22, vjust = -2, margin = margin(0,20,20,0)),
  108. axis.text = element_text(color = "black", size = 18),
  109. legend.key.size = unit(1,"cm"))
  110. pal = wes_palette("FantasticFox1", n = 5)
  111. plotSila = function(dat, cohort) {
  112. # dat = osila_adni
  113. (p_sila1 =
  114. dat %>%
  115. ggplot(.) +
  116. geom_line(data=dat,aes(x=age,val,group=subid, col = factor(conv)),alpha=0.6, size=0.5) +
  117. geom_point(data=dat,aes(x=age,val,group=subid, col = factor(conv)),stat="identity",alpha=1, size=0.5) +
  118. scale_color_manual(values = c(pal[2], pal[5])) +
  119. # geom_smooth(method = "gam", col = "black", se = F) +
  120. ggtitle(cohort) +
  121. labs(x = "Age") +
  122. theme_classic() + mytheme)
  123. (p_sila2 =
  124. dat %>%
  125. ggplot(.) +
  126. geom_line(data=dat,aes(x=estdtt0,val,group=subid, col = factor(conv)),alpha=0.6, size=0.5) +
  127. geom_point(data=dat,aes(x=estdtt0,val,group=subid, col = factor(conv)),stat="identity",alpha=1, size=0.5) +
  128. scale_color_manual(values = c(pal[2], pal[5])) +
  129. geom_hline(yintercept = dat$valt0, linetype = 2, col = "black") +
  130. ggtitle(cohort) +
  131. labs(x = "Years to Aβ+ (SILA)") +
  132. theme_classic() + mytheme)
  133. return(list(p_sila1 = p_sila1, p_sila2 = p_sila2, threshold = dat$valt0[1]))
  134. }
  135. p_sila_adni = plotSila(osila_adni, "ADNI")
  136. p_sila_bacs = plotSila(osila_bacs, "BACS")
  137. p_sila_lcbc = plotSila(osila_lcbc, "LCBC")
  138. p_sila_adni$p_sila2
  139. p_sila_bacs$p_sila2
  140. p_sila_lcbc$p_sila2
  141. if (savefigs) {
  142. ggsave(filename = "/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_sila_adni.pdf",
  143. plot = p_sila_adni$p_sila2 + theme(legend.position = "none"),
  144. width = 13,
  145. height = 13,
  146. dpi = 600,
  147. units = "cm",
  148. device = cairo_pdf
  149. )
  150. ggsave(filename = "/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_sila_bacs.pdf",
  151. plot = p_sila_bacs$p_sila2 + theme(legend.position = "none"),
  152. width = 13,
  153. height = 13,
  154. dpi = 600,
  155. units = "cm",
  156. device = cairo_pdf
  157. )
  158. ggsave(filename = "/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_sila_lcbc_threshcorrect.pdf",
  159. plot = p_sila_lcbc$p_sila2 + theme(legend.position = "none"),
  160. width = 13,
  161. height = 13,
  162. dpi = 600,
  163. units = "cm",
  164. device = cairo_pdf
  165. )
  166. }
  167. DF_SILA = rbind(osila_adni,
  168. osila_bacs,
  169. osila_lcbc)
  170. DF_SILA$visit_age = DF_SILA$age
  171. DF_SILA$subject_id %in% DF$subject_id
  172. DF_SILA$subject_id[!DF_SILA$subject_id %in% DF$subject_id]
  173. DF_SILA$age_at_sila_threshold = DF_SILA$age - DF_SILA$estdtt0
  174. DF_SILA %>%
  175. filter(subject_id == "002_S_4213") %>%
  176. pull(age_at_sila_threshold) %>%
  177. dput()
  178. # fix four subjects that have very slightly different age at threshold across their observations
  179. (checkSubs = DF_SILA %>%
  180. group_by(subject_id) %>%
  181. summarise(n_unique = n_distinct(round(age_at_sila_threshold, 4))) %>%
  182. filter(n_unique != 1)
  183. )
  184. DF_SILA[DF_SILA$subject_id == "021_S_4276",]
  185. DF_SILA[DF_SILA$subject_id == "031_S_4021",]
  186. DF_SILA[DF_SILA$subject_id == "036_S_4491",]
  187. DF_SILA[DF_SILA$subject_id == "1100591",]
  188. # by taking their last estimate
  189. DF_SILA$age_at_sila_threshold[DF_SILA$subject_id == "021_S_4276"] = DF_SILA$age_at_sila_threshold[DF_SILA$subject_id == "021_S_4276"][4]
  190. DF_SILA$age_at_sila_threshold[DF_SILA$subject_id == "031_S_4021"] = DF_SILA$age_at_sila_threshold[DF_SILA$subject_id == "031_S_4021"][3]
  191. DF_SILA$age_at_sila_threshold[DF_SILA$subject_id == "036_S_4491"] = DF_SILA$age_at_sila_threshold[DF_SILA$subject_id == "036_S_4491"][4]
  192. DF_SILA$age_at_sila_threshold[DF_SILA$subject_id == "1100591"] = DF_SILA$age_at_sila_threshold[DF_SILA$subject_id == "1100591"][2]
  193. DF_SILA$age_at_sila_threshold = round(DF_SILA$age_at_sila_threshold, 3)
  194. DF_SILA %>%
  195. group_by(subject_id) %>%
  196. summarise(n_unique = n_distinct(age_at_sila_threshold)) %>%
  197. filter(n_unique != 1)
  198. DF = left_join(DF,
  199. DF_SILA %>% select(subject_id, age_at_sila_threshold, conv) %>% distinct()
  200. )
  201. DF$visit_age
  202. DF$time_from_sila_threshold = DF$age_at_sila_threshold - DF$visit_age
  203. DF$time_from_sila_threshold_flip = DF$time_from_sila_threshold*-1
  204. head(DF %>% select(matches("age|time", ignore.case = TRUE)))
  205. # NB! this is correctly 76 (not 77) due to the negative centiloid slope BACS person -------
  206. # and this person had 10 MRI scans
  207. # hence the difference between 477 scans (in this analysis) and max 487 MRI scans in converters (in paper) is correct
  208. load("/cluster/projects/p274/projects/p040-ad_change/Berkeley/reproduce/data/DF.convallMRI.rda")
  209. length(unique(DF.convallMRI$subject_id)); dim(DF.convallMRI)
  210. DF.convallMRI$diff_mriAge_predABpos
  211. # choose to estimate via original method (linear estimates)
  212. # or SILA
  213. estType = "SILA"
  214. convonly = 1
  215. estType = "ORIG"
  216. if (estType != "SILA") {
  217. # if not SILA analysis (original with converters only)
  218. DF = DF.convallMRI
  219. dim(DF)
  220. length(unique(DF$subject_id))
  221. converters_allMRI_negfirst_BACS[converters_allMRI_negfirst_BACS$SID == "B16-220",] %>% dim()
  222. convonly = 0
  223. } else if (estType == "SILA") {
  224. # if SILA analysis (review)
  225. DF = DF %>% filter(!is.na(time_from_sila_threshold))
  226. dim(DF)
  227. length(unique(DF$subject_id))
  228. length(unique(DF$subject_id[DF$conv == 1]))
  229. # if testing SILA across only converter group
  230. if (convonly) {
  231. dim(DF %>% filter(conv == 1))
  232. DF %<>% filter(conv == 1)
  233. }
  234. }
  235. # high ab region map
  236. frontal_regions_lh <- c(
  237. "lh_superiorfrontal_thickness.aparcnative71",
  238. "lh_rostralmiddlefrontal_thickness.aparcnative71",
  239. "lh_caudalmiddlefrontal_thickness.aparcnative71",
  240. "lh_parsopercularis_thickness.aparcnative71",
  241. "lh_parstriangularis_thickness.aparcnative71",
  242. "lh_parsorbitalis_thickness.aparcnative71",
  243. "lh_lateralorbitofrontal_thickness.aparcnative71",
  244. "lh_medialorbitofrontal_thickness.aparcnative71",
  245. "lh_frontalpole_thickness.aparcnative71"
  246. )
  247. frontal_regions_rh <- c(
  248. "rh_superiorfrontal_thickness.aparcnative71",
  249. "rh_rostralmiddlefrontal_thickness.aparcnative71",
  250. "rh_caudalmiddlefrontal_thickness.aparcnative71",
  251. "rh_parsopercularis_thickness.aparcnative71",
  252. "rh_parstriangularis_thickness.aparcnative71",
  253. "rh_parsorbitalis_thickness.aparcnative71",
  254. "rh_lateralorbitofrontal_thickness.aparcnative71",
  255. "rh_medialorbitofrontal_thickness.aparcnative71",
  256. "rh_frontalpole_thickness.aparcnative71"
  257. )
  258. parietalregions = c(
  259. "lh_precuneus_thickness.aparcnative71",
  260. "rh_precuneus_thickness.aparcnative71",
  261. "lh_inferiorparietal_thickness.aparcnative71",
  262. "rh_inferiorparietal_thickness.aparcnative71",
  263. "lh_supramarginal_thickness.aparcnative71",
  264. "rh_supramarginal_thickness.aparcnative71"
  265. )
  266. cingulate_regions = c(
  267. "lh_posteriorcingulate_thickness.aparcnative71",
  268. "rh_posteriorcingulate_thickness.aparcnative71",
  269. "lh_isthmuscingulate_thickness.aparcnative71",
  270. "rh_isthmuscingulate_thickness.aparcnative71",
  271. "lh_rostralanteriorcingulate_thickness.aparcnative71",
  272. "rh_rostralanteriorcingulate_thickness.aparcnative71",
  273. "lh_caudalanteriorcingulate_thickness.aparcnative71",
  274. "rh_caudalanteriorcingulate_thickness.aparcnative71"
  275. )
  276. temporal_regions = c(
  277. "lh_middletemporal_thickness.aparcnative71",
  278. "rh_middletemporal_thickness.aparcnative71"
  279. )
  280. ab_regions_high = c(frontal_regions_lh, frontal_regions_rh, parietalregions, temporal_regions, cingulate_regions)
  281. # low ab regions - everything else
  282. ROIs[!ROIs %in% ab_regions_high]
  283. ab_regions_low = ROIs[!ROIs %in% ab_regions_high]
  284. ab_regions_low = ab_regions_low[!grepl("Mean", ab_regions_low)]
  285. # FDR regions in thickness analysis + homologues
  286. FDR_mask = c(frontal_regions_lh, frontal_regions_rh,
  287. "lh_precentral_thickness.aparcnative71",
  288. "rh_precentral_thickness.aparcnative71",
  289. "lh_paracentral_thickness.aparcnative71",
  290. "rh_paracentral_thickness.aparcnative71",
  291. "lh_insula_thickness.aparcnative71",
  292. "rh_insula_thickness.aparcnative71",
  293. "lh_supramarginal_thickness.aparcnative71",
  294. "rh_supramarginal_thickness.aparcnative71"
  295. )
  296. # minus frontal poles which were not FDR sig
  297. FDR_mask = FDR_mask[!grepl("pole", FDR_mask)]
  298. ROIs = FDR_mask
  299. # reverse years to AB to be correct (-years to AB)
  300. if (estType != "SILA") {
  301. DF$diff_mriAge_predABpos_flip = DF$diff_mriAge_predABpos*-1
  302. } else if (estType == "SILA") {
  303. DF$diff_mriAge_predABpos_flip = DF$time_from_sila_threshold_flip
  304. }
  305. DF$brainvarLow = rowMeans(DF[,ab_regions_low])
  306. DF$brainvarHigh = rowMeans(DF[,ab_regions_high])
  307. DF$subject_id = as.factor(DF$subject_id)
  308. fullDF = DF
  309. if (estType != "SILA") {
  310. facSmooth = T
  311. } else {
  312. facSmooth = F
  313. }
  314. if (facSmooth) {
  315. # ordered factor approach to get test statistics for GAMM interaction
  316. dat = DF
  317. dat$brainvarfac = dat$brainvarHigh
  318. stackdat = rbind(
  319. dat %>% mutate(highlow = "high"),
  320. dat %>% mutate(highlow = "low")
  321. )
  322. stackdat$brainvarfac[stackdat$highlow == "low"] = dat$brainvarLow
  323. stackdat = mutate(stackdat,
  324. ohighlow = factor(highlow, levels = c("low","high"),ordered = T))
  325. gamm.trajectories = gamm4(brainvarfac ~ s(diff_mriAge_predABpos_flip, by = as.factor(highlow)) + as.factor(highlow) + visit_age + subject_sex + cohort + scanStrength + ICV,
  326. data = stackdat, random = ~ (1 |subject_id))
  327. gamm.sum = summary(gamm.trajectories$gam)
  328. g = gamm.trajectories$gam
  329. plot.gam(g)
  330. # estimate smooth for set reflevel and a smoothed difference between ref and other levels
  331. ogamm.trajectories = gamm4(brainvarfac ~ as.factor(highlow) + s(diff_mriAge_predABpos_flip) + s(diff_mriAge_predABpos_flip, by = ohighlow) + visit_age + subject_sex + cohort + scanStrength + ICV,
  332. data = stackdat, random = ~ (1 |subject_id))
  333. ogamm.sum = summary(ogamm.trajectories$gam)
  334. plot.gam(ogamm.trajectories$gam)
  335. # thickness trajectory in high Aβ regions was significantly different than low Aβ regions
  336. ogamm.sum
  337. }
  338. # three analyses to run through - select which here
  339. regionTest = "high"
  340. regionTest = "low"
  341. regionTest = "cortex"
  342. if (regionTest == "high") {
  343. loopend = 1
  344. } else if (regionTest == "low") {
  345. loopend = 1
  346. } else if (regionTest == "cortex") {
  347. loopend = length(ROIs)
  348. }
  349. for (i in 1:loopend) {
  350. # tic()
  351. print(paste(i,"/",length(ROIs)))
  352. if (i == 1) {
  353. derivMat = gratiaderivMat = gratiaderivCIlwrMat = gratiaderivCIuprMat = matrix(NA, nrow = 1000, ncol = length(ROIs))
  354. fitMat = matrix(NA, nrow = 100, ncol = length(ROIs))
  355. RR = list()
  356. p_derivs = p_derivs_se = list()
  357. yearsBeforepredAB_on_ci_exclusion = c()
  358. yearsBeforepredAB_on_se_exclusion = c()
  359. maxaccels = c()
  360. }
  361. DF = fullDF
  362. setTxtProgressBar(pb,i)
  363. set.seed(123)
  364. # ab regions low / high
  365. if (regionTest == "high") {
  366. ROI = "high AB composite"
  367. DF$brainvar = rowMeans(DF[,ab_regions_high])
  368. palcol = pal[5]
  369. anaTitle = "Aβ high"
  370. }
  371. if (regionTest == "low") {
  372. ROI = "low AB composite"
  373. DF$brainvar = rowMeans(DF[,ab_regions_low])
  374. palcol = pal[2]
  375. anaTitle = "Aβ low"
  376. }
  377. if (regionTest == "cortex") {
  378. ROI = ROIs[i]
  379. DF$brainvar = DF[[ROI]]
  380. palcol = "darkgrey"
  381. anaTitle = ROI
  382. }
  383. g_convall = gamm4(brainvar ~ s(diff_mriAge_predABpos_flip) + visit_age + subject_sex + cohort + scanStrength + ICV, data = DF, random = ~ (1 | subject_id))
  384. g_convall_mgcv = gam(
  385. brainvar ~
  386. s(diff_mriAge_predABpos_flip) +
  387. s(subject_id, bs = "re") +
  388. visit_age + subject_sex + cohort + scanStrength + ICV,
  389. data = DF,
  390. method = "REML"
  391. )
  392. summary(g_convall$gam)
  393. g_sum = summary(g_convall_mgcv)
  394. RR[[i]] = g_sum
  395. lmm_convall = lmer(
  396. brainvar ~ diff_mriAge_predABpos_flip + visit_age + subject_sex + cohort + scanStrength + ICV + (1 | subject_id),
  397. data = DF
  398. )
  399. # plot.gam(g_convall$gam, residuals = T)
  400. summary(lmm_convall)
  401. # clearly the covariates are important
  402. ggplot(DF, aes(y=brainvar, x = diff_mriAge_predABpos_flip)) + geom_point(aes(group = subject_id)) + geom_smooth(method = "gam")
  403. plot(effect("diff_mriAge_predABpos_flip", lmm_convall, residuals=TRUE)) #warning is due to scaling of Y and X
  404. predictions <- DF %>%
  405. mutate(visit_age = mean(DF$visit_age), subject_sex = "Female", cohort = "ADNINC", scanStrength = "1-5T", ICV=0) %>%
  406. select(diff_mriAge_predABpos_flip, visit_age,subject_sex,ICV,mri_info_site_name,scanStrength, cohort) %>%
  407. predict(g_convall$gam, newdata = ., se.fit = T)
  408. residualsg <- residuals(g_convall$mer)
  409. DF$partial_residuals = predictions$fit + residualsg
  410. DF$fit = predictions$fit
  411. DF$sefit = predictions$se.fit
  412. DF$cifit = predictions$se.fit*1.96
  413. #colour palette ---
  414. pal = wesanderson::wes_palettes$FantasticFox1
  415. pointcol = "#6faca8"
  416. #colour palette ---
  417. if (estType != "SILA") {
  418. tmpDF = DF %>% filter(diff_mriAge_predABpos >= 1)
  419. } else {
  420. tmpDF = DF %>% filter(time_from_sila_threshold >= 1)
  421. }
  422. (fig1 =
  423. DF %>% #filter(subject_id != adnioutlier) %>%
  424. ggplot(.) +
  425. geom_line(data=tmpDF,aes(x=diff_mriAge_predABpos_flip,partial_residuals,group=subject_id),color=pointcol,alpha=0.6, size=0.5) +
  426. geom_point(data=tmpDF,aes(x=diff_mriAge_predABpos_flip,partial_residuals,group=subject_id),color=pointcol,stat="identity",alpha=1, size=0.5) +
  427. # geom_ribbon(data=dug,aes(x=diff_mriAge_predABpos_flip,ymin=fit-CI,ymax=fit+CI),alpha=.7,show.legend=F,fill="dark grey") +
  428. geom_line(data=tmpDF,aes(x=diff_mriAge_predABpos_flip,y=fit),col="black") +
  429. ggtitle(ROI) +
  430. labs(x = "Age") +
  431. theme_classic() + mytheme)
  432. # Extract plotting data without rendering the plot
  433. plot_data = plot.gam(g_convall$gam, select = 1, se = TRUE, rug = FALSE, shade = T, pages = 0)
  434. # get gam intercept
  435. g_sum = summary(g_convall$gam)
  436. g_sum$p.coeff
  437. # The output is a list, extract x, fit, and se
  438. df = data.frame(
  439. x = plot_data[[1]]$x,
  440. fit = plot_data[[1]]$fit + g_sum$p.coeff[1],
  441. se = plot_data[[1]]$se
  442. )
  443. # Calculate upper and lower confidence intervals
  444. df$upper = df$fit + 1 * df$se #NB! help(plot.gam) shows it is already using CI
  445. df$lower = df$fit - 1 * df$se
  446. ggplot(df, aes(x = x, y = fit)) +
  447. geom_line() +
  448. geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.2) +
  449. labs(
  450. ) +
  451. theme_minimal()
  452. # Approximate first derivative
  453. df$deriv = c(NA, diff(df$fit) / diff(df$x))
  454. # Find index of minimum (i.e., where uptick starts)
  455. min_idx = which.min(df$fit)
  456. # Optionally, find first point where derivative turns positive
  457. first_uptick_idx = which(df$deriv > 0 & seq_along(df$deriv) > min_idx)[1]
  458. # Get corresponding x-value
  459. uptick_point = df$x[first_uptick_idx]
  460. uptick_pointy = df$fit[first_uptick_idx]
  461. fitMat[,i] = df$fit
  462. (pderiv0 = ggplot(df, aes(x = x, y = fit)) +
  463. geom_line() +
  464. labs(
  465. x = "Years to Aβ+",
  466. y = "Thickness"
  467. ) +
  468. # geom_point(aes(x = uptick_point, y = uptick_pointy), col = "black", size = 5) +
  469. theme_minimal())
  470. (pderiv0_ci = ggplot(df, aes(x = x, y = fit)) +
  471. geom_line(col = palcol) +
  472. ggtitle(ROI) +
  473. geom_ribbon(aes(ymin = lower, ymax = upper), alpha = 0.1, col = palcol, fill = palcol) +
  474. labs(
  475. x = "Years to Aβ+",
  476. y = "Thickness"
  477. ) +
  478. # geom_point(aes(x = uptick_point, y = uptick_pointy), col = "black", size = 5) +
  479. theme_minimal())
  480. # first derivative
  481. df$deriv = c(NA, diff(df$fit) / diff(df$x))
  482. df$deriv_lower = c(NA, diff(df$lower) / diff(df$x))
  483. df$deriv_upper = c(NA, diff(df$upper) / diff(df$x))
  484. (pderiv1 = ggplot(df, aes(x = x, y = deriv)) +
  485. geom_line() +
  486. geom_hline(yintercept = 0, linetype = "dashed") +
  487. labs(x = "Years to Aβ+", y = "Rate of change") +
  488. theme_minimal())
  489. (pderiv1_se = ggplot(df, aes(x = x, y = deriv)) +
  490. geom_line() +
  491. geom_ribbon(aes(ymin = deriv_lower, ymax = deriv_upper), alpha = 0.2) +
  492. geom_hline(yintercept = 0, linetype = "dashed") +
  493. labs(x = "Years to Aβ+", y = "Rate of change") +
  494. theme_minimal())
  495. derivMat[,i] = df$deriv
  496. # Compute second derivative (numerical)
  497. second_derivative = diff(diff(df$fit)) / diff(df$x[-1])
  498. # Align x-axis (midpoints between x values)
  499. second_x = df$x[-c(1, 2)] + diff(df$x)[-1] / 2
  500. #point of maximum accerelated change
  501. maxaccel_y = second_derivative[which(second_derivative == max(second_derivative))]
  502. maxaccel_x = second_x[which(second_derivative == max(second_derivative))]
  503. if (length(maxaccel_x) > 1) {
  504. maxaccel_y = NA
  505. maxaccel_x = NA
  506. }
  507. if (is.na(maxaccel_x)) {
  508. maxaccels[i] = NA
  509. } else {
  510. maxaccels[i] = maxaccel_x
  511. pderiv2 = ggplot(data.frame(x = second_x, second_derivative = second_derivative), aes(x = x, y = second_derivative)) +
  512. geom_line() +
  513. geom_hline(yintercept = 0, linetype = "dashed") +
  514. labs(y = "Acceleration", x = "Years to Aβ+") +
  515. geom_point(aes(x = maxaccel_x[i], y = maxaccel_y[i]), col = "black", size = 2) +
  516. theme_minimal()
  517. # check all derivatives
  518. (pcheckderiv = cowplot::plot_grid(pderiv0, pderiv1, pderiv2, nrow = 3))
  519. }
  520. # NB! se of calculated derivative not ideal - using gratia instead
  521. (psumse1 = cowplot::plot_grid(pderiv0_ci, pderiv1_se, nrow = 3))
  522. # Compute first derivative of the smooth term
  523. d1 = gratia::derivatives(g_convall_mgcv, term = "s(diff_mriAge_predABpos_flip)", interval = "confidence", n = 1000)
  524. d1 = as.data.frame(d1)
  525. d1$.lower_ci[which(d1$.lower_ci > 0)]
  526. # point at which the derivative CI excluded zero used to estimate the rank order of thickness changes
  527. cross_point = which(d1$.lower_ci > 0)[1]
  528. data.frame(d1$diff_mriAge_predABpos_flip, d1$.lower_ci, logical = d1$.lower_ci > 0)
  529. if (is.na(cross_point)) {
  530. print("CIs do not exclude zero")
  531. yearsBeforepredAB_on_ci_exclusion[i] = "never"
  532. exclude0 = 0
  533. } else if (cross_point == 1) {
  534. print("CIs always exclude zero")
  535. yearsBeforepredAB_on_ci_exclusion[i] = "always"
  536. cross_y = 0
  537. cross_x = d1$diff_mriAge_predABpos_flip[cross_point]
  538. exclude0 = 1
  539. } else {
  540. print("CIs exclude zero")
  541. cross_y = d1$.lower_ci[cross_point]
  542. cross_x = d1$diff_mriAge_predABpos_flip[cross_point]
  543. yearsBeforepredAB_on_ci_exclusion[i] = cross_x
  544. exclude0 = 1
  545. }
  546. #repeat for SE (since not all cross)
  547. d1$upper_se = d1$.derivative + d1$.se
  548. d1$lower_se = d1$.derivative - d1$.se
  549. # point at which the derivative SE excluded zero
  550. cross_point_se = which(d1$lower_se > 0)[1]
  551. # two instances where the deriv excluded zero on the downward trajectory - fixed to first point on upward trajectory
  552. data.frame(d1$diff_mriAge_predABpos_flip, d1$lower_se, logical = d1$lower_se > 0)
  553. # if (estType == "SILA" & convonly == 0) { if (i == 12) { cross_point_se = 420 } } # fix the one across full group
  554. # if (estType == "SILA" & convonly == 0) { if (i == 2) { cross_point_se = 320 } } # fix the one across full group
  555. # if (estType == "SILA" & convonly == 0) { if (i == 9) { cross_point_se = 537 } } # fix the one across full group
  556. # if (estType == "SILA" & convonly == 0) { if (i == 10) { cross_point_se = 322 } } # fix the one across full group
  557. # if (estType == "SILA" & convonly == 1) { if (i == 4) { cross_point_se = 262 } } # fix if only converters
  558. # if (estType == "SILA" & convonly == 1) { if (i == 2) { cross_point_se = 281 } } # fix the one across full group
  559. # if (estType == "SILA" & convonly == 1) { if (i == 15) { cross_point_se = 296 } } # fix the one across full group
  560. # if (estType == "SILA" & convonly == 1) { if (i == 21) { cross_point_se = NA } } # fix the one across full group
  561. if (is.na(cross_point_se)) {
  562. print("SEs do not exclude zero")
  563. yearsBeforepredAB_on_se_exclusion[i] = "never"
  564. } else if (cross_point_se == 1) {
  565. print("SEs always exclude zero")
  566. cross_yse = 0
  567. cross_xse = d1$diff_mriAge_predABpos_flip[cross_point_se]
  568. yearsBeforepredAB_on_se_exclusion[i] = "always"
  569. } else {
  570. print("SEs exclude zero")
  571. cross_yse = d1$lower_se[cross_point_se]
  572. cross_xse = d1$diff_mriAge_predABpos_flip[cross_point_se]
  573. yearsBeforepredAB_on_se_exclusion[i] = cross_xse
  574. }
  575. # check crossing points
  576. if (!is.na(cross_point)) {
  577. ggplot(d1, aes(x = diff_mriAge_predABpos_flip, y = .derivative)) +
  578. geom_line() +
  579. geom_ribbon(aes(ymin = .lower_ci, ymax = .upper_ci), alpha = 0.1) +
  580. geom_hline(yintercept = 0, linetype = "dashed") +
  581. geom_point(aes(x = cross_x, y = cross_y), col = "black", size = 5)
  582. }
  583. if (!is.na(cross_point_se) & cross_point_se != 1) {
  584. ggplot(d1, aes(x = diff_mriAge_predABpos_flip, y = .derivative)) +
  585. geom_line() +
  586. geom_ribbon(aes(ymin = lower_se, ymax = upper_se), alpha = 0.1) +
  587. geom_hline(yintercept = 0, linetype = "dashed") +
  588. geom_point(aes(x = cross_xse, y = cross_yse), col = "black", size = 5)
  589. }
  590. (pderiv1_gratia_ci = ggplot(d1, aes(x = diff_mriAge_predABpos_flip, y = .derivative)) +
  591. geom_line(col = palcol) +
  592. geom_ribbon(aes(ymin = .lower_ci, ymax = .upper_ci), alpha = 0.1, colour = palcol, fill = palcol) +
  593. geom_hline(yintercept = 0, linetype = "dashed") +
  594. labs(
  595. x = "Years to Aβ+",
  596. y = "First derivative"
  597. ) +
  598. # geom_point(aes(x = cross_x, y = cross_y), col = "black", size = 1) +
  599. theme_classic() + mytheme
  600. )
  601. (pderiv1_gratia_se = ggplot(d1, aes(x = diff_mriAge_predABpos_flip, y = .derivative)) +
  602. geom_line() +
  603. geom_ribbon(aes(ymin = lower_se, ymax = upper_se), alpha = 0.2) +
  604. geom_hline(yintercept = 0, linetype = "dashed") +
  605. labs(
  606. x = "Years to Aβ+",
  607. y = "First derivative"
  608. ) +
  609. # geom_point(aes(x = cross_xse, y = cross_yse), col = "black", size = 1) +
  610. theme_classic() + mytheme
  611. )
  612. if (regionTest == "cortex") {
  613. if (!is.na(cross_point)) {
  614. # add crossing point to plot
  615. pderiv1_gratia_ci = pderiv1_gratia_ci + geom_point(aes(x = cross_x, y = cross_y), size = 6, fill = "#cbac09", col = "#cbac09")
  616. }
  617. if (!is.na(cross_point_se)) {
  618. pderiv1_gratia_se = pderiv1_gratia_se + geom_point(aes(x = cross_xse, y = cross_yse), size = 6, fill = "#cbac09", col = "#cbac09")
  619. }
  620. }
  621. # save gratia outputs
  622. gratiaderivMat[,i] = d1$.derivative
  623. gratiaderivCIlwrMat[,i] = d1$.lower_ci
  624. gratiaderivCIuprMat[,i] = d1$.upper_ci
  625. # main plot
  626. (
  627. p_combine_fitderiv_ci = ggpubr::ggarrange(
  628. pderiv0_ci + theme_classic() + mytheme + ggtitle(anaTitle) +
  629. pderiv1_gratia_ci,
  630. nrow = 1,
  631. align = "hv"
  632. )
  633. )
  634. (
  635. p_combine_fitderiv_se = ggpubr::ggarrange(
  636. pderiv0_ci + theme_classic() + mytheme + ggtitle(anaTitle) +
  637. pderiv1_gratia_se,
  638. nrow = 1,
  639. align = "hv"
  640. )
  641. )
  642. if (regionTest == "cortex") {
  643. (
  644. p_combine_fitderiv_ci = ggpubr::ggarrange(
  645. pderiv0_ci + theme_classic() + mytheme + ggtitle(anaTitle) + theme(axis.ticks = element_blank(), axis.line = element_blank()),
  646. pderiv1_gratia_ci + theme(axis.ticks = element_blank(), axis.line = element_blank()),
  647. nrow = 1,
  648. align = "hv"
  649. )
  650. )
  651. }
  652. p_derivs[[i]] = p_combine_fitderiv_ci
  653. p_derivs_se[[i]] = p_combine_fitderiv_se
  654. if (savefigs == 1) {
  655. if (regionTest == "high") {
  656. print("saving high plot")
  657. # ggsave(plot = p_combine_fitderiv_ci,
  658. # filename = paste0("/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_thickTraj_ABhigh.pdf"),
  659. # width=20, height=9, units="cm", dpi=600, device = cairo_pdf
  660. # )
  661. } else if (regionTest == "low") {
  662. print("saving low plot")
  663. # ggsave(plot = p_combine_fitderiv_ci,
  664. # filename = paste0("/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_thickTraj_ABlow.pdf"),
  665. # width=20, height=9, units="cm", dpi=600, device = cairo_pdf
  666. # )
  667. } else {
  668. # ggsave(plot = p_combine_fitderiv_ci,
  669. # filename = paste0("/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_thickTraj_", ROI, ".pdf"),
  670. # width=20, height=9, units="cm", dpi=600, device = cairo_pdf
  671. # )
  672. }
  673. }
  674. }
  675. # check cross point on all 24 roi derivs
  676. p_derivs[[1]]
  677. p_derivs[[2]]
  678. p_derivs[[3]]
  679. p_derivs[[4]]
  680. p_derivs[[5]]
  681. p_derivs[[6]]
  682. p_derivs[[7]]
  683. p_derivs[[8]]
  684. p_derivs[[9]]
  685. p_derivs[[10]]
  686. p_derivs[[11]]
  687. p_derivs[[12]]
  688. p_derivs[[13]]
  689. p_derivs[[14]]
  690. p_derivs[[15]]
  691. p_derivs[[16]]
  692. p_derivs[[17]]
  693. p_derivs[[18]]
  694. p_derivs[[19]]
  695. p_derivs[[20]]
  696. p_derivs[[21]]
  697. p_derivs[[22]]
  698. p_derivs[[23]]
  699. p_derivs[[24]]
  700. p_derivs_se[[1]]
  701. p_derivs_se[[2]]
  702. p_derivs_se[[3]]
  703. p_derivs_se[[4]]
  704. p_derivs_se[[5]]
  705. p_derivs_se[[6]]
  706. p_derivs_se[[7]]
  707. p_derivs_se[[8]]
  708. p_derivs_se[[9]]
  709. p_derivs_se[[10]]
  710. p_derivs_se[[11]]
  711. p_derivs_se[[12]]
  712. p_derivs_se[[13]]
  713. p_derivs_se[[14]]
  714. p_derivs_se[[15]]
  715. p_derivs_se[[16]]
  716. p_derivs_se[[17]]
  717. p_derivs_se[[18]]
  718. p_derivs_se[[19]]
  719. p_derivs_se[[20]]
  720. p_derivs_se[[21]]
  721. p_derivs_se[[22]]
  722. p_derivs_se[[23]]
  723. p_derivs_se[[24]]
  724. # all confirmed correct
  725. # rank order on thickness change
  726. data.frame(yearsBeforepredAB_on_ci_exclusion,
  727. yearsBeforepredAB_on_se_exclusion
  728. )
  729. rankThickTraj = data.frame(rois = ROIs,
  730. rankedThickTraj = yearsBeforepredAB_on_ci_exclusion,
  731. rankedThickTrajSE = yearsBeforepredAB_on_se_exclusion,
  732. rankedThickTrajMaxAccel = maxaccels)
  733. # set as 0 if CI always excludes 0
  734. rankThickTraj$rankedThickTraj[rankThickTraj$rankedThickTraj == "always"] = 0
  735. rankThickTraj$rankedThickTraj[rankThickTraj$rankedThickTraj == "never"] = NA
  736. rankThickTraj$rankedThickTrajSE[rankThickTraj$rankedThickTrajSE == "always"] = 0
  737. rankThickTraj$rankedThickTrajSE[rankThickTraj$rankedThickTrajSE == "never"] = NA
  738. rankThickTraj$rankedThickTraj = as.numeric(rankThickTraj$rankedThickTraj)
  739. rankThickTraj$rankedThickTrajSE = as.numeric(rankThickTraj$rankedThickTrajSE)
  740. # rank and reorder ROIs based on the point at which the CI / SE of the derivative crosses 0
  741. # NB! no need to reverse as yearsBeforepredAB was flipped in model (diff_mriAge_predABpos_flip)
  742. # CI
  743. rankThickTraj$rankedThickTrajRev <- ifelse(
  744. is.na(rankThickTraj$rankedThickTraj),
  745. NA,
  746. ifelse(rankThickTraj$rankedThickTraj == 0,
  747. 0,
  748. rank(rankThickTraj$rankedThickTraj, ties.method = "first"))
  749. )
  750. rankThickTraj %<>% arrange(rankedThickTrajRev)
  751. # SE
  752. rankThickTraj$rankedThickTrajSERev <- ifelse(
  753. is.na(rankThickTraj$rankedThickTrajSE),
  754. NA,
  755. ifelse(rankThickTraj$rankedThickTrajSE == 0,
  756. 0,
  757. rank(rankThickTraj$rankedThickTrajSE, ties.method = "first"))
  758. )
  759. rankThickTraj %<>% arrange(rankedThickTrajSERev)
  760. # load in amyloid order
  761. rankAB = fread(file.path(b, "reproduce/data/rankABpredTraj.csv"))
  762. rankAB %<>% rename(rankedABTraj = rankedTraj,
  763. rankedABTrajRev = revRankedTraj)
  764. rankThickTraj$rois = paste0("CTX_", toupper(gsub("_thickness.aparcnative71", "", rankThickTraj$rois)), "_SUVR")
  765. rankThickTraj$rois %in% rankAB$rois
  766. rankedBoth = merge(
  767. rankThickTraj, rankAB
  768. )
  769. # filter data where there is no rank order for thickness (i.e. ROI derivative did not exclude 0 and thus could not be ranked)
  770. rankedBoth_cut = rankedBoth %>% filter(!is.na(rankedThickTrajRev))
  771. # make ranking plots
  772. rankedBoth$roi = gsub("CTX_", "", rankedBoth$rois)
  773. rankedBoth$roi = gsub("_SUVR", "", rankedBoth$roi)
  774. rankedBoth$roi = tolower(rankedBoth$roi)
  775. orderplot = arrange(rankedBoth, rankedABTrajRev) %>% select(roi)
  776. rankedBoth$roi = factor(rankedBoth$roi, levels = rev(orderplot$roi))
  777. rankRange = range(rankedBoth$rankedABTrajRev, na.rm= T)
  778. table(rankedBoth$rankedABTrajRev)
  779. rankedBoth$rankedABTrajRev = rankedBoth$rankedABTrajRev-1 # make 0 indexed (so colours match up with thickness rank plot)
  780. (p_rankAB_FDRregions = ggplot(rankedBoth %>%
  781. arrange(rankedABTrajRev),
  782. aes(x = rankedABTrajRev, y = factor(roi, levels = rev(unique(roi))))) +
  783. geom_bar(aes(x=rankedABTrajRev, y =roi), stat = "identity", colour = "grey", alpha = 0.5, width = 0.01, size=0.5) +
  784. geom_point(aes(colour = rankedABTrajRev), fill = "white", shape = 21, stroke = 2, size = 5) +
  785. scale_colour_viridis(option = "E", direction = -1, name = "Rank", limits = c(0, rankRange[2]), oob = scales::squish) +
  786. theme_classic() +
  787. mytheme +
  788. labs(x = "Rank (Aβ)",y = NULL) + theme(legend.position = "none")
  789. )
  790. # ggsave(plot = p_rankAB_FDRregions,
  791. # filename = paste0("/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_rankAB_FDRregions.png"),
  792. # width=7, height=26, units="cm", dpi=600)
  793. # ensure rank plot for thickness is ordered the same
  794. (p_rankThick_frontal = ggplot(rankedBoth,
  795. aes(x = rankedThickTrajRev, y = factor(roi, levels = rev(unique(roi))))) +
  796. geom_bar(aes(x=rankedThickTrajRev, y =roi), stat = "identity", colour = "grey", alpha = 0.5, width = 0.01, size=0.5) +
  797. geom_point(aes(colour = rankedThickTrajRev), fill = "white", shape = 21, stroke = 2, size = 5) +
  798. scale_colour_viridis(option = "E", direction = -1, name = "Rank", limits = c(0, rankRange[2]), oob = scales::squish) +
  799. theme_classic() +
  800. mytheme +
  801. labs(x = "Rank (Thickness)",y = NULL) + theme(legend.position = "none")
  802. )
  803. table(rankedBoth$rankedThickTrajSERev)
  804. (p_rankThick_frontal_bySE = ggplot(rankedBoth,
  805. aes(x = rankedThickTrajSERev, y = factor(roi, levels = rev(unique(roi))))) +
  806. geom_bar(aes(x=rankedThickTrajSERev, y =roi), stat = "identity", colour = "grey", alpha = 0.5, width = 0.01, size=0.5) +
  807. geom_point(aes(colour = rankedThickTrajSERev), fill = "white", shape = 21, stroke = 2, size = 5) +
  808. scale_colour_viridis(option = "E", direction = -1, name = "Rank", limits = c(0, rankRange[2]), oob = scales::squish) +
  809. theme_classic() +
  810. mytheme +
  811. labs(x = "Rank (Thickness)",y = NULL) + theme(legend.position = "none")
  812. )
  813. cp1 = cowplot::plot_grid(p_rankAB_FDRregions, p_rankThick_frontal + theme(axis.text.y = element_text(color = "transparent"), axis.line.y = element_blank(), axis.ticks.y = element_blank()))
  814. cp2 = cowplot::plot_grid(p_rankAB_FDRregions, p_rankThick_frontal_bySE + theme(axis.text.y = element_text(color = "transparent"), axis.line.y = element_blank(), axis.ticks.y = element_blank()))
  815. # ggsave(plot = p_rankAB_FDRregions,
  816. # filename = paste0("/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_rankAB_FDRregions.pdf"),
  817. # width=12, height=26, units="cm", dpi=600, device = cairo_pdf)
  818. # ggsave(plot = p_rankThick_frontal,
  819. # filename = paste0("/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_rankRThick_FDRregions.pdf"),
  820. # width=12, height=26, units="cm", dpi=600, device = cairo_pdf)
  821. table(rankedBoth_cut$rankedThickTrajRev)
  822. pear1 = cor.test(rankedBoth_cut$rankedThickTrajRev, rankedBoth_cut$rankedABTrajRev)
  823. pear2 = cor.test(rankedBoth_cut$rankedThickTrajSERev, rankedBoth_cut$rankedABTrajRev)
  824. pval1 = format(
  825. tidy(pear1)$p.value[1],
  826. scientific = TRUE, digits = 2)
  827. bval1 = round(
  828. tidy(pear1)$estimate[1],
  829. digits = 2)
  830. pval2 = format(
  831. tidy(pear2)$p.value[1],
  832. scientific = TRUE, digits = 2)
  833. bval2 = round(
  834. tidy(pear2)$estimate[1],
  835. digits = 2)
  836. table(rankedBoth_cut$rankedThickTrajRev)
  837. # correlation plot based on CI (fig 5g)
  838. (p_rankCI = ggplot(rankedBoth_cut, aes(x = rankedThickTrajRev, y = rankedABTrajRev)) +
  839. geom_point(aes(col = rankedThickTrajRev), size = 3) +
  840. scale_colour_viridis(option = "E", direction = -1, name = "Rank", limits = c(0, rankRange[2]), oob = scales::squish) +
  841. theme_classic() +
  842. mytheme +
  843. # coord_fixed() +
  844. geom_smooth(method = "lm", se = T, col = "black", alpha = .1) +
  845. labs(x = "Rank (Thickness)",y = "Rank (Aβ)") + theme(legend.position = "none") +
  846. ggtitle("order of CIs excluding 0") +
  847. annotate("text", x = 1, y = max(rankedBoth_cut$rankedABTrajRev)+2, label = paste("p =", pval1), color = "black", hjust = 0) +
  848. annotate("text", x = 1, y = max(rankedBoth_cut$rankedABTrajRev)+3, label = paste("B =", bval1), color = "black", hjust = 0)
  849. )
  850. # ggsave(plot = p_rankCI,
  851. # filename = paste0("/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_rankCI.pdf"),
  852. # width=9, height=12, units="cm", dpi=600, device = cairo_pdf)
  853. # ggsave(plot = p_rankCI,
  854. # filename = paste0("/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_rankCI_", estType, "convonly", convonly, ".pdf"),
  855. # width=9, height=12, units="cm", dpi=600, device = cairo_pdf)
  856. table(rankedBoth_cut$rankedThickTrajSERev)
  857. # correlation plot based on SE (fig 5h)
  858. (p_rankSE = ggplot(rankedBoth_cut, aes(x = rankedThickTrajSERev, y = rankedABTrajRev)) +
  859. geom_point(aes(col = rankedThickTrajSERev), size = 3) +
  860. scale_colour_viridis(option = "E", direction = -1, name = "Rank", limits = c(0, rankRange[2]), oob = scales::squish) +
  861. theme_classic() +
  862. mytheme +
  863. # coord_fixed() +
  864. geom_smooth(method = "lm", se = T, col = "black", alpha = .2) +
  865. labs(x = "Rank (Thickness)",y = "Rank (Aβ)") + theme(legend.position = "none") +
  866. ggtitle("order of SEs excluding 0") +
  867. annotate("text", x = 1, y = max(rankedBoth_cut$rankedABTrajRev)+2, label = paste("p =", pval2), color = "black", hjust = 0) +
  868. annotate("text", x = 1, y = max(rankedBoth_cut$rankedABTrajRev)+3, label = paste("B =", bval2), color = "black", hjust = 0)
  869. )
  870. # ggsave(plot = p_rankSE,
  871. # filename = paste0("/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_rankSE.pdf"),
  872. # width=9, height=12, units="cm", dpi=600, device = cairo_pdf)
  873. # ggsave(plot = p_rankSE,
  874. # filename = paste0("/cluster/projects/p274/projects/p040-ad_change/Berkeley/paper2/figs_yearsBeforeAB/p_rankSE_", estType, "convonly", convonly, ".pdf"),
  875. # width=9, height=12, units="cm", dpi=600, device = cairo_pdf)

10-rankThicknessChange.r at commit 8606e75, under MIT · at the source

Overview

Authors: James M. Roe1,2, William J. Jagust3, Susan M. Landau3, Theresa M. Harrison3, Håkon Grydeland1, Maksim Slivka1, José-Luis Alatorre-Warren1, Pablo F. Garrido1, Øystein Sørensen1, Edvard O. S. Grødem1,2, Tyler J. Ward3, Esten H. Leonardsen1,4, Alice Murphy3, JiaQie Lee3, Tormod Fladby5,6, Atle Bjørnerud1,2, Kristine B. Walhovd1,2, Anders M. Fjell1,2, Didac Vidal-Piñeiro1, Yunpeng Wang1
  1. Center for Lifespan Changes in Brain and Cognition (LCBC), Department of Psychology, University of Oslo,Oslo, Norway
  2. Computational Radiology and Artificial Intelligence, Department of Radiology and Nuclear Medicine, Oslo University Hospital,Oslo, Norway
  3. Department of Neuroscience, University of California, Berkeley,Berkeley, CA USA
  4. Centre for Precision Psychiatry, Oslo University Hospital & Institute of Clinical Medicine, University of Oslo,Oslo, Norway
  5. Department of Neurology, Akershus University Hospital,Lørenskog, Norway
  6. Institute for Clinical Medicine, University of Oslo,Oslo, Norway
Journal: Nature neuroscience, volume 29, issue 9, pages 2164-2175
Dates: received 24 August 2025; accepted 9 June 2026; published online 19 August 2026; in print 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1038/s41593-026-02363-4 · PMID 42618753 · PMCID PMC13533846 · OpenAlex W7203752607
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: structural MRI / diffusion (modality), PET / SPECT (modality), human (organism), Alzheimer's / dementia (population)
Methods: Statistics, Connectivity, Smoothing, state filtering, decompositions, Preprocessing
Keywords: Neural ageing, Predictive markers
MeSH: Alzheimer Disease*, Amyloid beta-Peptides*, Cerebral Cortex*, Aged, Aged, 80 and over, Disease Progression, Female, Humans, Longitudinal Studies, Magnetic Resonance Imaging, Male, Positron-Emission Tomography (* major topic)
Topic: Dementia and Cognitive Impairment Research (Psychiatry and Mental health, Medicine), according to OpenAlex
Citations: cited by 1 paper (Europe PMC); 68 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repository

Its files are read in the Code ↔ Paper reader above, with 6 matches between paragraphs and lines of code.

jamesmroe/yearsBeforeAB

License: MIT
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 8606e753805b25245b52466dbf4d2c26cb94a43a, 7 May 2026
Languages: R (14), Shell (1)
Size: 264 files, 15 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, license file, environment (requirements.txt), documentation
Not found: CITATION.cff, tests, continuous integration
Tools: tidyverse (14 files), data.table (12 files), broom (8 files), cowplot (7 files), ggpubr (6 files), mgcv (5 files), patchwork (4 files), easystats (3 files), ggseg (3 files), ggplot2 (2 files), lmerTest (2 files), lme4 (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
17 files

Code availability statement

The paper has a code availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s41593-026-02363-4.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 15 scripts, each with its path and the digest of its content;
  • 6 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data availability statement

The paper has a data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

  • it says that the data are available on request

Read it in the paper: doi.org/10.1038/s41593-026-02363-4.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 2, 28 September 2026

  • Publisher: n/a → Nature Portfolio

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 20 authors, 2 keywords, 12 MeSH terms, 2 funders, 65 references.

Cite

This paper

Roe, J. M., Jagust, W. J., Landau, S. M., Harrison, T. M., Grydeland, H., Slivka, M., Alatorre-Warren, J.-L., Garrido, P. F., Sørensen, Ø., Grødem, E. O. S., Ward, T. J., Leonardsen, E. H., Murphy, A., Lee, J., Fladby, T., Bjørnerud, A., Walhovd, K. B., Fjell, A. M., Vidal-Piñeiro, D., & Wang, Y. (2026). Cortical thickness changes precede high levels of amyloid by at least 7 years. Nature neuroscience, 29(9), 2164-2175. https://doi.org/10.1038/s41593-026-02363-4

BibTeX

@article{roe2026cortical,
author = {Roe, James M. and Jagust, William J. and Landau, Susan M. and Harrison, Theresa M. and Grydeland, Håkon and Slivka, Maksim and Alatorre-Warren, José-Luis and Garrido, Pablo F. and Sørensen, Øystein and Grødem, Edvard O. S. and Ward, Tyler J. and Leonardsen, Esten H. and Murphy, Alice and Lee, JiaQie and Fladby, Tormod and Bjørnerud, Atle and Walhovd, Kristine B. and Fjell, Anders M. and Vidal-Piñeiro, Didac and Wang, Yunpeng},
title = {{Cortical thickness changes precede high levels of amyloid by at least 7 years}},
journal = {Nature neuroscience},
year = {2026},
month = aug,
volume = {29},
number = {9},
pages = {2164--2175},
publisher = {Nature Portfolio},
issn = {1097-6256},
doi = {10.1038/s41593-026-02363-4},
url = {https://doi.org/10.1038/s41593-026-02363-4},
pmid = {42618753},
pmcid = {PMC13533846}
}

RIS

TY - JOUR
AU - Roe, James M.
AU - Jagust, William J.
AU - Landau, Susan M.
AU - Harrison, Theresa M.
AU - Grydeland, Håkon
AU - Slivka, Maksim
AU - Alatorre-Warren, José-Luis
AU - Garrido, Pablo F.
AU - Sørensen, Øystein
AU - Grødem, Edvard O. S.
AU - Ward, Tyler J.
AU - Leonardsen, Esten H.
AU - Murphy, Alice
AU - Lee, JiaQie
AU - Fladby, Tormod
AU - Bjørnerud, Atle
AU - Walhovd, Kristine B.
AU - Fjell, Anders M.
AU - Vidal-Piñeiro, Didac
AU - Wang, Yunpeng
TI - Cortical thickness changes precede high levels of amyloid by at least 7 years
T2 - Nature neuroscience
J2 - Nat Neurosci
PY - 2026
DA - 2026/08/19
VL - 29
IS - 9
SP - 2164
EP - 2175
SN - 1097-6256
PB - Nature Portfolio
DO - 10.1038/s41593-026-02363-4
UR - https://doi.org/10.1038/s41593-026-02363-4
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41593-026-02363-4",
"type": "article-journal",
"title": "Cortical thickness changes precede high levels of amyloid by at least 7 years",
"container-title": "Nature neuroscience",
"author": [
{
"family": "Roe",
"given": "James M."
},
{
"family": "Jagust",
"given": "William J."
},
{
"family": "Landau",
"given": "Susan M."
},
{
"family": "Harrison",
"given": "Theresa M."
},
{
"family": "Grydeland",
"given": "Håkon"
},
{
"family": "Slivka",
"given": "Maksim"
},
{
"family": "Alatorre-Warren",
"given": "José-Luis"
},
{
"family": "Garrido",
"given": "Pablo F."
},
{
"family": "Sørensen",
"given": "Øystein"
},
{
"family": "Grødem",
"given": "Edvard O. S."
},
{
"family": "Ward",
"given": "Tyler J."
},
{
"family": "Leonardsen",
"given": "Esten H."
},
{
"family": "Murphy",
"given": "Alice"
},
{
"family": "Lee",
"given": "JiaQie"
},
{
"family": "Fladby",
"given": "Tormod"
},
{
"family": "Bjørnerud",
"given": "Atle"
},
{
"family": "Walhovd",
"given": "Kristine B."
},
{
"family": "Fjell",
"given": "Anders M."
},
{
"family": "Vidal-Piñeiro",
"given": "Didac"
},
{
"family": "Wang",
"given": "Yunpeng"
}
],
"container-title-short": "Nat Neurosci",
"volume": "29",
"issue": "9",
"page": "2164-2175",
"DOI": "10.1038/s41593-026-02363-4",
"PMID": "42618753",
"PMCID": "PMC13533846",
"ISSN": "1097-6256",
"publisher": "Nature Portfolio",
"URL": "https://doi.org/10.1038/s41593-026-02363-4",
"language": "en",
"issued": {
"date-parts": [
[
2026,
8,
19
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1162/imag.a.1242 [code]
Stable individual differences dominate adult brain volume variation until later life.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: structural MRI / diffusion, 2 references, 4 authors
[2] doi:10.1162/imag.a.1196 [code]
Failure to detect entorhinal grid-like signals in a passive navigation human fMRI study.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: lmerTest, tidyverse, 3 authors
[3] doi:10.1016/j.tjpad.2026.100622 [code]
The time interval from amyloid to tau PET positivity varies by age, sex and APOE-ε4 status.
Journal: The journal of prevention of Alzheimer's disease
In common: broom, lmerTest, lme4, 3 other tools, PET / SPECT, Alzheimer's / dementia, 5 references
[4] doi:10.1002/alz.71609
Cortical gray-white matter contrast alterations precede amyloid-β positivity and macrostructural changes in older adults without dementia.
Journal: Alzheimer's & dementia : the journal of the Alzheimer's Association
In common: PET / SPECT, Alzheimer's / dementia, structural MRI / diffusion, 9 references
[5] doi:10.1002/alz.71567 [code]
Associations of dementia polyexposure scores to Alzheimer's disease endophenotypes in a diverse population.
Journal: Alzheimer's & dementia : the journal of the Alzheimer's Association
In common: easystats, broom, cowplot, 4 other tools, PET / SPECT, Alzheimer's / dementia, 4 references
[6] doi:10.1038/s41398-026-04010-9 [code]
Bullying victimization and brain development: a longitudinal structural magnetic resonance imaging study from adolescence to early adulthood.
Journal: Translational psychiatry
In common: ggseg, easystats, broom, 7 other tools, structural MRI / diffusion
[7] doi:10.1093/brain/awaf413 [code]
Estimating the time course of biomarker changes in Alzheimer's disease.
Journal: Brain : a journal of neurology
In common: PET / SPECT, Alzheimer's / dementia, structural MRI / diffusion, 9 references
[8] doi:10.1093/braincomms/fcag176 [code]
Tau topography subtypes account for clinical heterogeneity and longitudinal trajectories in early-onset Alzheimer's disease.
Journal: Brain communications
In common: easystats, lmerTest, lme4, 4 other tools, PET / SPECT, Alzheimer's / dementia, 3 references
[9] doi:10.1162/imag.a.1235 [code]
Intracranial volume: To adjust or not to adjust? It is not a matter of if, but how.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: ggseg, broom, lmerTest, 6 other tools, structural MRI / diffusion, 1 reference
[10] doi:10.1002/hbm.70605 [code]
BrainEnrich: Revealing Biological Insights for Imaging-Derived Phenotypes Through Transcriptomic Enrichment.
Journal: Human brain mapping
In common: ggseg, easystats, broom, 6 other tools, 1 reference

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.