This file contains all the source code to generate the figures and statistical measures reported in the paper Evolution and Spread of Politeness Systems in Indo-European
Required data files
ie-v1.nex
(a sample of bayesian phylogenetic trees for
the I-E language family; Dunn and Tresoldi 2021)ie-v1.mcc.tre
(a Maximum Clade Consistency tree
summarising the tree sample, for reference only)language.metadata.csv
(ISO codes, geographic
coordinates, and ancient/modern status)SAE-features.csv
(presence/absence of SAE areal
features, coded from Haspelmath list)../data/pronoun-paradigms.csv
(an etic grid showing the
pronominal forms used for each pronominal function attested in the
family)Generated files:
pronoun-similarity.csv
(a pairwise similarity table,
generated from pronoun-paradigms.csv
using the python
script ../data/make-pronoun-similarity-table.py
; for each
language each pair of pronominal functions are rated 1/same pronoun or
0/different pronouns)pronoun-number-conflation.csv
(generated from
pronoun-paradigms.csv
with the script
../data/make_pronoun_conflation_table.py
; does the language
ever conflate singular and plural for 2nd or 3rd person)pronoun-distinct-politeness.csv
(generated from
pronoun-paradigms.csv
with the script
../data/make_pronoun_distinct_politeness_table.py
; does the
language have distinct politeness forms in the 2sg and the 2pl?)trees.rData
(saved intermediate results of this
analysis)simmap.rData
(saved intermediate results of this
analysis)results.rData
(saved results of this analysis)To regenerate the analysis cleanly you need to delete the three
.rData
files, otherwise saved values will be used. The
tree.sample.size
variable is set at 400, which is an
acceptable value for the full test, but this is slow and it can be set
to a lower value for testing.
#library(logisticPCA)
library(ape)
library(vegan)
## Loading required package: permute
## Loading required package: lattice
## This is vegan 2.5-7
library(parallel)
library(phytools)
## Loading required package: maps
##
## Attaching package: 'phytools'
## The following object is masked from 'package:vegan':
##
## scores
library(rnaturalearth)
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────── tidyverse 1.3.1 ──
## ✔ ggplot2 3.4.0 ✔ purrr 0.3.4
## ✔ tibble 3.1.8 ✔ dplyr 1.0.10
## ✔ tidyr 1.1.4 ✔ stringr 1.4.0
## ✔ readr 1.4.0 ✔ forcats 0.5.1
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ✖ purrr::map() masks maps::map()
library(ggrepel)
library(gridExtra) # for grid.arrange
##
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
##
## combine
options(ggrepel.max.overlaps = Inf)
MC.CORES <- detectCores() # Use all available processing power
cat(paste("--> Using", MC.CORES, "cores\n"))
## --> Using 12 cores
As a sanity check, transform the pronoun paradigm similarities into an inter-language distance measure. A cluster plot of the distance matrix showing structurally similar languages clustered together. Note that this is not a phylogeny!
# The similarity features are comparisions of every pair of cells in a pronoun paradigm,
# calculated per language
pairwise.similarity <- read.delim("pronoun-similarity.csv", row.names=1, header=TRUE)
language.distance <- dist(pairwise.similarity, method="manhattan") / ncol(pairwise.similarity)
plot(hclust(language.distance), cex=0.5)
Prepare metadata
metadata <- read_tsv("language-metadata.csv")
##
## ── Column specification ────────────────────────────────────────────────────────
## cols(
## language = col_character(),
## iso.code = col_character(),
## latitude = col_double(),
## longitude = col_double(),
## ancient = col_logical()
## )
sae.features <- read.delim("SAE-features.csv", row.names=1)
sae.sum <- apply(sae.features, 1, sum)[metadata$language]
metadata$sae.score <- sae.sum
metadata$SAE <- sae.sum > 4
metadata
#View(metadata)
Summarise data with PCA
# temporary fix for missing values
sae.features[is.na(sae.features)] <- 0
pca_model <- prcomp(language.distance, scale=TRUE)$x %>%
as.data.frame() %>%
mutate(language=rownames(.)) %>%
left_join(metadata) %>%
filter(!is.na(iso.code)) # rm non-IE languages
## Joining, by = "language"
pca_model %>%
ggplot(aes(x=PC1, y=PC2, label=language, colour=SAE)) +
geom_point() +
scale_colour_manual(values=c("darkgray", "black")) +
geom_text_repel(size=3, segment.size=0.25, segment.alpha=0.5, box.padding=0.1) +
theme(legend.position = "none")
ggsave("../figures/Figure_2_PCA.png", width=5.75, height=5.75, units="in")
ggsave("../figures/Figure_2_PCA.pdf", width=5.75, height=5.75, units="in")
Supplementary figure 1 shows that PC1 can be characterised as
distinguishing languages which have person-number conflation,
operationalised as the answer to the question does the language ever
conflate singular and plural for 2nd or 3rd person?; this is
calculated from the pronoun paradigm data in
pronoun-paradigms.csv
using the script
make_pronoun_conflation_table.py
. Languages with
person-number conflation tend to be loaded negatively on PC1.
pca_model %>%
left_join(read_tsv("pronoun-number-conflation.csv")) %>%
ggplot(aes(x=PC1, y=PC2, label=language, colour=as.factor(conflation))) +
geom_point() +
geom_text_repel(size=3, segment.size=0.25, segment.alpha=0.5, box.padding=0.1) +
labs(colour="Conflated\nnumber")
##
## ── Column specification ────────────────────────────────────────────────────────
## cols(
## language = col_character(),
## conflation = col_double()
## )
## Joining, by = "language"
ggsave("../figures/Supplementary_Figure_1.pdf", width=5.75, height=5.75, units="in")
Supplementary figure 2 shows that PC2 distinguishes languages which have distinct politeness forms in the singular and plural (languages with distinct politeness forms in the singular and plural are weighted positively); note that while this is a distinctive feature of IE pronominal paradigms, it does not seem to be diagnostic of the SAE linguistic area.
pca_model %>%
left_join(read_tsv("pronoun-distinct-politeness.csv")) %>%
ggplot(aes(x=PC1, y=PC2, label=language, colour=as.factor(distinct))) +
geom_point() + #geom_point(aes(shape=SAE)) +
geom_text_repel(size=3, segment.size=0.25, segment.alpha=0.5, box.padding=0.1) +
labs(colour="Distinct\npoliteness")
##
## ── Column specification ────────────────────────────────────────────────────────
## cols(
## language = col_character(),
## distinct = col_double()
## )
## Joining, by = "language"
ggsave("../figures/Supplementary_Figure_2.pdf", width=5.75, height=5.75, units="in")
Prepare the tree sample if the file trees.rData
doesn’t
already exist (this is a slow process, so we don’t want to repeat it if
not necessary). To force regeneration of trees.rData
delete
the current version of the file along with other .rData
files.
Sanity check: Load a reference tree, fix the tree labels, and plot it
all.languages <- metadata %>% pull(language)
namehash <- c( # convert tree names to names used in analysis or to proxy languages
# proxies are languages which are in the equivalent position in the tree
"Arvanitika"="Albanian_Gheg",
"Tosk"="Albanian_Tosk",
"Eastern_Armenian"="Armenian",
"Belarusian"="Byelorussian",
"Irish"="Irish_A",
"Digor_Ossetic"="Iron_Ossetic",
"Luxembourgish"="Luxemburgish",
"Bihari"="Maithili",
"Old_Church_Slavic"="Old_Church_Slavonic",
"Old_West_Norse"="Old_Norse",
"Cagliari"="Sardinian_Campidanese",
"Nuorese"="Sardinian_Logudorese",
"Serbian"="Serbocroatian",
"Singhalese"="Sinhalese",
"Welsh"="Welsh_N")
mcc.tre <- read.nexus("ie-v1.mcc.tre")
mcc.tre$tip.label <- recode(mcc.tre$tip.label, !!!namehash)
mcc.tre <- ladderize(root(keep.tip(mcc.tre, all.languages), "Hittite"))
plot(mcc.tre, no.margin=TRUE, cex=0.6)
states.pca <- data.frame(
PC1=round(pca_model$PC1,5),
PC2=round(pca_model$PC2,5)) #,
#feat.sum=pca_model$sae.score)
row.names(states.pca) <- pca_model$language
tree.sample.size <- 400 # set this to e.g. 20 for testing, 400+ for a full analysis
if (!file.exists("trees.rData")){
TREEFILE <- "ie-v1.nex" # this sample is 10000 trees, which is much too long
trees <- read.nexus(TREEFILE)
# drop the first half of the trees as burnin, and filter the remaining sample to a reasonable size
trees <- trees[seq(length(trees)/2, length(trees), length.out=tree.sample.size)]
tree.list <- mclapply(trees,
function(tree) {
# fix labels
tree$tip.label <- recode(tree$tip.label, !!!namehash)
# scale edge lengths (there are sometimes errors when numbers are too large)
tree$edge.length <- tree$edge.length / 1000
# root on Hittite
ladderize(root(keep.tip(tree, all.languages), "Hittite"))
},
mc.cores=MC.CORES)
class(tree.list) <- "multiPhylo"
save(tree.list, states.pca, mcc.tre, file="trees.rData")
}
Plot these states on a map.
world = ne_countries(scale = "small", returnclass = "sf")
ggplot(data=world) +
geom_sf(fill="white") +
coord_sf(xlim = range(metadata$longitude), ylim = range(metadata$latitude)) +
geom_point(data=metadata, aes(x = longitude, y = latitude, shape=ancient, fill=as.factor(sae.score)), size=3, colour="black") +
scale_shape_manual(values=c(21,23))+
scale_fill_grey(start=1, end=0.2) +
theme(legend.position = "none", axis.title.x=element_blank(), axis.title.y=element_blank())
ggsave("../figures/Figure_1_Map.pdf", width=5.75, height=3.75, units="in")
ggsave("../figures/Figure_1_Map.png", width=5.75, height=3.75, units="in")
Plot the distribution of SAE feature counts
metadata %>%
ggplot(aes(x=sae.score)) +
geom_histogram(binwidth=1) +
scale_x_continuous(breaks=0:9) +
xlab("Number of SAE Features") + ylab("Number of languages")
There is a natural breakpoint at sae.score >= 5, which we will thus
use as a threshold for membership of the SAE area. This is the same
breakpoint suggested by Haspelmath 2011:1505.
ggsave("../figures/Figure_3_SAE.png", width=3, height=2)
ggsave("../figures/Figure_3_SAE.pdf", width=3, height=2)
observed.states <- metadata %>% pull(SAE) %>% as.integer()
names(observed.states) <- metadata %>% pull(language)
# make.simmap rate models: "ARD" all rates different; "SYM" symmetrical; "EQ"" equal; or use matrix
dollo.model = matrix(c(0,0,1,0), 2) # once a lineage becomes SAE it doesn't revert to non-SAE
simmap.tre <- make.simmap(mcc.tre,
observed.states,
model=dollo.model)
## make.simmap is sampling character histories conditioned on
## the transition matrix
##
## Q =
## 0 1
## 0 -0.0001069 0.0001069
## 1 0.0000000 0.0000000
## (estimated using likelihood);
## and (mean) root node prior probabilities
## pi =
## 0 1
## 0.5 0.5
## Done.
cols <- c("black", "gray")
names(cols) <- c("0", "1")
plotSimmap(simmap.tre, cols, fsize=0.5, pts=FALSE, lwd=4)
Create all the simmaps. This can be an extremely slow process, so the results are saved.
Plot three arbitrary simmaps to show variation in tree structure (from the Bayesian phylogenetic sampling process) and simulated history
opar <- par(no.readonly=TRUE)
par(mfrow=c(1,3))
plot.simmap.i <- function(i){
cols <- c("black", "gray")
names(cols) <- c("0", "1")
plot(simmap.list[[i]], cols, fsize=0.5, pts=FALSE, lwd=4)}
plot.simmap.i(1)
plot.simmap.i(2)
plot.simmap.i(3)
par(opar)
pdf("../figures/Figure_4_State_Simulation.pdf", width=7, height=4.5)
par(mfrow=c(1,3))
plot.simmap.i(1)
plot.simmap.i(2)
plot.simmap.i(3)
dev.off()
## quartz_off_screen
## 2
Now do the brownie.lite
test (O’Meara et al. 2006).
NTREES <- length(simmap.list)
results.trait.m <- matrix( # template results matrix
nrow=NTREES,
ncol=12,
dimnames=list(1:NTREES,
c("BM.singlerate","logL.singlerate", "k1", "1rate.AICc", "NonSAE.rate",
"SAE.rate","logL.multiplerate", "k2", "2rate.AICc", "pchisq",
"converged", "delta.AICc"))
)
if (!file.exists("results.rData")){
process.results <- function(trait.name){
results.trait.name <- results.trait.m
traits <- states.pca[[trait.name]]
names(traits) <- row.names(states.pca)
for (i in 1:NTREES){
cat(paste("Trait ", trait.name, " trial ", i, "/", NTREES, "\n", sep=""))
# check that labels are aligned
stopifnot(all(sort(simmap.list[[i]]$tip.label) == sort(names(traits))))
fit <- NA
tryCatch(
fit <- brownie.lite(simmap.list[[i]], traits, test="chisq"),
error=function(e) {}
)
if (length(fit) != 1){
# calculate AICc for 1 and 2 rate models
fit1aicc<-(-2*fit$logL1+2*fit$k1+((2*fit$k1*(fit$k1+1))/(90-fit$k1-1)))
fit2aicc<-(-2*fit$logL.multiple+2*fit$k2+((2*fit$k2*(fit$k2+1))/(90-fit$k2-1)))
results.trait.name[i,]<- as.numeric(c(
fit$sig2.single,
fit$logL1,
fit$k1,
fit1aicc,
fit$sig2.multiple[sort(names(fit$sig2.multiple))][[1]],
fit$sig2.multiple[sort(names(fit$sig2.multiple))][[2]],
fit$logL.multiple,
fit$k2,
fit2aicc,
fit$P.chisq,
fit$convergence == "Optimization has converged.",
fit1aicc-fit2aicc
))
}
}
results.trait.name
}
results <- mclapply(names(states.pca), process.results,
mc.cores=min(MC.CORES, length(names(states.pca))))
names(results) <- names(states.pca)
save(results, file="results.rData")
} else load("results.rData")
Get rate estimates (report in article text)
trait_labels <- c("PC1", "PC2")
# trait_labels <- c("PC1", "PC2", "feat.sum")
lapply(trait_labels, function(d) as_tibble(results[[d]])) %>%
set_names(trait_labels) %>%
bind_rows(.id="trait") %>%
pivot_longer(c("logL.singlerate", "logL.multiplerate"), names_to="model", values_to="rate") %>%
group_by(trait, model) %>%
summarise(median_rate=median(rate))
## `summarise()` has grouped output by 'trait'. You can override using the
## `.groups` argument.
Compare AIC for one rate and two rate models
trait_labels <- c("PC1", "PC2")
# trait_labels <- c("PC1", "PC2", "feat.sum")
lapply(trait_labels, function(d) as_tibble(results[[d]])) %>%
set_names(trait_labels) %>%
bind_rows(.id="trait") %>%
pivot_longer(c("1rate.AICc", "2rate.AICc"), names_to="model", values_to="AICc") %>%
ggplot(aes(x=trait, y=AICc, colour=model)) + geom_boxplot()
Change in AIC gives a measure of how much one model should be preferred over the other
fig5c <- lapply(trait_labels, function(d) as_tibble(results[[d]])) %>%
set_names(trait_labels) %>%
bind_rows(.id="trait") %>%
ggplot(aes(x=trait, y=delta.AICc)) +
geom_boxplot() +
labs(title="(c)") +
theme(axis.title.x=element_blank())
fig5c
Report median change in AICc in text
lapply(trait_labels, function(d) as_tibble(results[[d]])) %>%
set_names(trait_labels) %>%
bind_rows(.id="trait") %>%
group_by(trait) %>%
summarise(median.delta.AIC.c=median(delta.AICc), evidence.ratio=exp(0.5*median(delta.AICc)))
For the two rate model, how the estimated rates of evolution of each component in the SAE and non-SAE regions of the trees.
fig5a <- lapply(trait_labels, function(d) as_tibble(results[[d]])) %>%
set_names(trait_labels) %>%
bind_rows(.id="trait" ) %>%
pivot_longer(c("SAE.rate", "NonSAE.rate"), names_to="area", values_to="rate") %>%
mutate(area=if_else(area=="SAE.rate", "SAE", "non-SAE")) %>%
ggplot(aes(x=trait, y=rate, fill=area)) +
geom_boxplot() +
theme(legend.position = "bottom") +
scale_fill_grey(start=0.5, end=0.8)+
labs(title="(a)") +
theme(axis.title.x=element_blank())
fig5a
Summarise the relative rate of evolution of each component for SAE versus non-SAE parts of the tree
fig5b <- lapply(trait_labels, function(d) as_tibble(results[[d]])) %>%
set_names(trait_labels) %>%
bind_rows(.id="trait" ) %>%
mutate(rate.multiplier=SAE.rate/NonSAE.rate) %>%
ggplot(aes(x=trait, y=rate.multiplier)) + geom_boxplot() +
labs(title="(b)") +
theme(axis.title.x=element_blank())
fig5b
lapply(trait_labels, function(d) as_tibble(results[[d]])) %>%
set_names(trait_labels) %>%
bind_rows(.id="trait" ) %>%
mutate(rate.multiplier=SAE.rate/NonSAE.rate) %>%
group_by(trait) %>%
summarise(median.rate.multiplier=median(rate.multiplier))
fig5 <- grid.arrange(fig5a, fig5b, fig5c, nrow=1)
ggsave("../figures/Figure_5_results.png", plot=fig5, width=7, height=3)
ggsave("../figures/Figure_5_results.pdf", plot=fig5, width=7, height=3)
Dunn, Michael and Tresoldi, Tiago. 2021. Indo-European Lexical Data (IELex) and ‘Good Enough’ Tree. Uppsala: Uppsala universitet. Available at: https://github.com/evotext/ielex-data-and-tree ; DOI: 10.5281/zenodo.5556801
Haspelmath, Martin. 2001. “The European Linguistic Area: Standard Average European.” Language Typology and Language Universals: An International Handbook 2: 1492–1510.
O’Meara, Brian .C., Cécile Ané, Michael J. Sanderson, and Peter C. Wainwright. 2006. Testing for different rates of continuous trait evolution using likelihood. Evolution 60(5): 922-933.
sessioninfo::session_info()
## ─ Session info ───────────────────────────────────────────────────────────────
## setting value
## version R version 4.0.4 (2021-02-15)
## os macOS Big Sur 10.16
## system x86_64, darwin17.0
## ui X11
## language (EN)
## collate en_US.UTF-8
## ctype en_US.UTF-8
## tz Europe/Stockholm
## date 2023-02-08
##
## ─ Packages ───────────────────────────────────────────────────────────────────
## package * version date lib source
## ape * 5.5 2021-04-25 [1] CRAN (R 4.0.2)
## assertthat 0.2.1 2019-03-21 [1] CRAN (R 4.0.2)
## backports 1.2.1 2020-12-09 [1] CRAN (R 4.0.2)
## broom 0.7.9 2021-07-27 [1] CRAN (R 4.0.2)
## bslib 0.2.5.1 2021-05-18 [1] CRAN (R 4.0.2)
## cellranger 1.1.0 2016-07-27 [1] CRAN (R 4.0.2)
## class 7.3-18 2021-01-24 [1] CRAN (R 4.0.4)
## classInt 0.4-3 2020-04-07 [1] CRAN (R 4.0.2)
## cli 3.4.1 2022-09-23 [1] CRAN (R 4.0.4)
## cluster 2.1.0 2019-06-19 [1] CRAN (R 4.0.4)
## clusterGeneration 1.3.7 2020-12-15 [1] CRAN (R 4.0.2)
## coda 0.19-4 2020-09-30 [1] CRAN (R 4.0.2)
## codetools 0.2-18 2020-11-04 [1] CRAN (R 4.0.4)
## colorspace 2.0-3 2022-02-21 [1] CRAN (R 4.0.5)
## combinat 0.0-8 2012-10-29 [1] CRAN (R 4.0.2)
## crayon 1.4.1 2021-02-08 [1] CRAN (R 4.0.2)
## DBI 1.1.1 2021-01-15 [1] CRAN (R 4.0.2)
## dbplyr 2.1.1 2021-04-06 [1] CRAN (R 4.0.2)
## digest 0.6.28 2021-09-23 [1] CRAN (R 4.0.2)
## dplyr * 1.0.10 2022-09-01 [1] CRAN (R 4.0.4)
## e1071 1.7-7 2021-05-23 [1] CRAN (R 4.0.2)
## ellipsis 0.3.2 2021-04-29 [1] CRAN (R 4.0.2)
## evaluate 0.14 2019-05-28 [1] CRAN (R 4.0.1)
## expm 0.999-6 2021-01-13 [1] CRAN (R 4.0.2)
## fansi 1.0.3 2022-03-24 [1] CRAN (R 4.0.5)
## farver 2.1.1 2022-07-06 [1] CRAN (R 4.0.4)
## fastmatch 1.1-3 2021-07-23 [1] CRAN (R 4.0.2)
## forcats * 0.5.1 2021-01-27 [1] CRAN (R 4.0.2)
## fs 1.5.0 2020-07-31 [1] CRAN (R 4.0.2)
## generics 0.1.3 2022-07-05 [1] CRAN (R 4.0.4)
## ggplot2 * 3.4.0 2022-11-04 [1] CRAN (R 4.0.4)
## ggrepel * 0.9.1 2021-01-15 [1] CRAN (R 4.0.2)
## glue 1.6.2 2022-02-24 [1] CRAN (R 4.0.5)
## gridExtra * 2.3 2017-09-09 [1] CRAN (R 4.0.2)
## gtable 0.3.1 2022-09-01 [1] CRAN (R 4.0.4)
## haven 2.3.1 2020-06-01 [1] CRAN (R 4.0.2)
## highr 0.8 2019-03-20 [1] CRAN (R 4.0.2)
## hms 1.0.0 2021-01-13 [1] CRAN (R 4.0.2)
## htmltools 0.5.1.1 2021-01-22 [1] CRAN (R 4.0.2)
## httr 1.4.2 2020-07-20 [1] CRAN (R 4.0.2)
## igraph 1.2.6 2020-10-06 [1] CRAN (R 4.0.2)
## jquerylib 0.1.4 2021-04-26 [1] CRAN (R 4.0.2)
## jsonlite 1.7.2 2020-12-09 [1] CRAN (R 4.0.2)
## KernSmooth 2.23-18 2020-10-29 [1] CRAN (R 4.0.4)
## knitr 1.31 2021-01-27 [1] CRAN (R 4.0.2)
## labeling 0.4.2 2020-10-20 [1] CRAN (R 4.0.2)
## lattice * 0.20-41 2020-04-02 [1] CRAN (R 4.0.4)
## lifecycle 1.0.3 2022-10-07 [1] CRAN (R 4.0.4)
## lubridate 1.8.0 2021-10-07 [1] CRAN (R 4.0.2)
## magrittr 2.0.3 2022-03-30 [1] CRAN (R 4.0.5)
## maps * 3.4.0 2021-09-25 [1] CRAN (R 4.0.2)
## MASS 7.3-53 2020-09-09 [1] CRAN (R 4.0.4)
## Matrix 1.3-2 2021-01-06 [1] CRAN (R 4.0.4)
## mgcv 1.8-33 2020-08-27 [1] CRAN (R 4.0.4)
## mnormt 2.0.2 2020-09-01 [1] CRAN (R 4.0.2)
## modelr 0.1.8 2020-05-19 [1] CRAN (R 4.0.2)
## munsell 0.5.0 2018-06-12 [1] CRAN (R 4.0.2)
## nlme 3.1-152 2021-02-04 [1] CRAN (R 4.0.4)
## numDeriv 2016.8-1.1 2019-06-06 [1] CRAN (R 4.0.2)
## permute * 0.9-5 2019-03-12 [1] CRAN (R 4.0.2)
## phangorn 2.7.1 2021-07-13 [1] CRAN (R 4.0.2)
## phytools * 0.7-90 2021-09-25 [1] CRAN (R 4.0.2)
## pillar 1.8.1 2022-08-19 [1] CRAN (R 4.0.4)
## pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.0.2)
## plotrix 3.8-2 2021-09-08 [1] CRAN (R 4.0.2)
## proxy 0.4-26 2021-06-07 [1] CRAN (R 4.0.2)
## purrr * 0.3.4 2020-04-17 [1] CRAN (R 4.0.2)
## quadprog 1.5-8 2019-11-20 [1] CRAN (R 4.0.2)
## R6 2.5.1 2021-08-19 [1] CRAN (R 4.0.2)
## Rcpp 1.0.9 2022-07-08 [1] CRAN (R 4.0.4)
## readr * 1.4.0 2020-10-05 [1] CRAN (R 4.0.2)
## readxl 1.3.1 2019-03-13 [1] CRAN (R 4.0.2)
## reprex 2.0.1 2021-08-05 [1] CRAN (R 4.0.2)
## rgeos 0.5-5 2020-09-07 [1] CRAN (R 4.0.2)
## rlang 1.0.6 2022-09-24 [1] CRAN (R 4.0.4)
## rmarkdown 2.17 2022-10-07 [1] CRAN (R 4.0.4)
## rnaturalearth * 0.1.0 2017-03-21 [1] CRAN (R 4.0.2)
## rstudioapi 0.13 2020-11-12 [1] CRAN (R 4.0.2)
## rvest 1.0.0 2021-03-09 [1] CRAN (R 4.0.2)
## s2 1.0.7 2021-09-28 [1] CRAN (R 4.0.2)
## sass 0.4.0 2021-05-12 [1] CRAN (R 4.0.2)
## scales 1.2.1 2022-08-20 [1] CRAN (R 4.0.4)
## scatterplot3d 0.3-41 2018-03-14 [1] CRAN (R 4.0.2)
## sessioninfo 1.1.1 2018-11-05 [1] CRAN (R 4.0.2)
## sf 1.0-3 2021-10-07 [1] CRAN (R 4.0.2)
## sp 1.4-5 2021-01-10 [1] CRAN (R 4.0.2)
## stringi 1.7.5 2021-10-04 [1] CRAN (R 4.0.2)
## stringr * 1.4.0 2019-02-10 [1] CRAN (R 4.0.2)
## tibble * 3.1.8 2022-07-22 [1] CRAN (R 4.0.4)
## tidyr * 1.1.4 2021-09-27 [1] CRAN (R 4.0.2)
## tidyselect 1.2.0 2022-10-10 [1] CRAN (R 4.0.4)
## tidyverse * 1.3.1 2021-04-15 [1] CRAN (R 4.0.2)
## tmvnsim 1.0-2 2016-12-15 [1] CRAN (R 4.0.2)
## units 0.7-1 2021-03-16 [1] CRAN (R 4.0.2)
## utf8 1.2.2 2021-07-24 [1] CRAN (R 4.0.2)
## vctrs 0.5.1 2022-11-16 [1] CRAN (R 4.0.4)
## vegan * 2.5-7 2020-11-28 [1] CRAN (R 4.0.2)
## withr 2.5.0 2022-03-03 [1] CRAN (R 4.0.5)
## wk 0.5.0 2021-07-13 [1] CRAN (R 4.0.2)
## xfun 0.34 2022-10-18 [1] CRAN (R 4.0.4)
## xml2 1.3.2 2020-04-23 [1] CRAN (R 4.0.2)
## yaml 2.2.1 2020-02-01 [1] CRAN (R 4.0.2)
##
## [1] /Library/Frameworks/R.framework/Versions/4.0/Resources/library