ggsave(histplot, file="../../MyStuff/Images/ggplot2-hist-cereal-100.png",
h=4, w=6, units="in", dpi=300)
histplot <- ggplot(data=cereal, aes(x=calories))+
ggtitle("Histogram of number of calories/serving")+
xlab("calories/serving")+ylab("Density")+
geom_histogram(binwidth=20 )
histplot
ggsave(histplot, file="../../MyStuff/Images/ggplot2-hist-cereal-101.png",
h=4, w=6, units="in", dpi=300)
histplot <- ggplot(data=cereal, aes(x=calories))+
ggtitle("Histogram of number of calories/serving")+
xlab("calories/serving")+ylab("Density")+
geom_histogram(aes(y=..density..),binwidth=20,alpha=0.2)+
geom_density(color='red')
histplot
ggsave(histplot, file="../../MyStuff/Images/ggplot2-hist-cereal-102.png",
h=4, w=6, units="in", dpi=300)
histplot <- ggplot(data=cereal, aes(x=calories))+
ggtitle("Histogram of number of calories/serving")+
xlab("calories/serving")+ylab("Density")+
geom_histogram(aes(y=..density..),binwidth=20,alpha=0.2)+
geom_density(color='red')+
facet_grid(shelfF~ .)
histplot
ggsave(histplot, file="../../MyStuff/Images/ggplot2-hist-cereal-103.png",
h=4, w=6, units="in", dpi=300)
#--------------------------------------------------------------
# Side-by-side box of calories by shelf
boxplot <- ggplot(data=cereal, aes(x=shelfF, y=calories))+
ggtitle("Boxplot of number of calories/serving by Shelf")+
ylab("calories/serving")+xlab("Shelf")+
geom_boxplot()
boxplot
ggsave(boxplot, file="../../MyStuff/Images/ggplot2-boxplot-cereal-001.png",
h=4, w=6, units="in", dpi=300)
boxplot <- ggplot(data=cereal, aes(x=shelfF, y=calories))+
ggtitle("Boxplot of number of calories/serving by Shelf")+
ylab("calories/serving")+xlab("Shelf")+
geom_boxplot(alpha=0.2, notch=TRUE)
boxplot
ggsave(boxplot, file="../../MyStuff/Images/ggplot2-boxplot-cereal-002.png",
h=4, w=6, units="in", dpi=300)
boxplot <- ggplot(data=cereal, aes(x=shelfF, y=calories))+
ggtitle("Boxplot of number of calories/serving by Shelf")+
ylab("calories/serving")+xlab("Shelf")+
geom_boxplot(alpha=0.2, notch=TRUE, outlier.size=0)+
geom_point(position=position_jitter(width=0.1))
boxplot
ggsave(boxplot, file="../../MyStuff/Images/ggplot2-boxplot-cereal-003.png",
h=4, w=6, units="in", dpi=300)
cereal$fiber.grp <- recode(cereal$fiber, "lo:3='low'; 3:hi='high'")
xtabs(~fiber.grp, data=cereal)
cereal$fiber.grpF <- factor(cereal$fiber.grp)
boxplot <- ggplot(data=cereal, aes(x=fiber.grpF, y=calories))+
ggtitle("Boxplot of number of calories/serving by Fiber Group")+
ylab("calories/serving")+xlab("Fiber Group")+
geom_boxplot(alpha=0.2, notch=TRUE, outlier.size=0)+
geom_point(position=position_jitter(width=0.1))
boxplot
ggsave(file="../../MyStuff/Images/ggplot2-boxplot-cereal-004.png",
h=4, w=6, units="in", dpi=300)
cereal$fiber.grpF <- factor(cereal$fiber.grp,
levels=c("low","high"), order=TRUE)
boxplot <- ggplot(data=cereal, aes(x=fiber.grpF, y=calories))+
ggtitle("Boxplot of number of calories/serving by Fiber Group")+
ylab("calories/serving")+xlab("Fiber Group")+
geom_boxplot(alpha=0.2, notch=TRUE, outlier.size=0)+
geom_point(position=position_jitter(width=0.1))
boxplot
ggsave(boxplot, file="../../MyStuff/Images/ggplot2-boxplot-cereal-004b.png",
h=4, w=6, units="in", dpi=300)
#--------------------------------------------------------------
# Exercise
library(readxl)
butts <- readxl::read_excel('../sampledata/bird-butts-data.xlsx',
sheet='Correlational',
col_names=TRUE,
trim_ws = TRUE,
skip=1)
names(butts) <- make.names(names(butts))
names(butts)[ grepl('wieght', names(butts))] <- "Butts.weight"
butts$log.mites <- log(butts$Number.of.mites)
birdbox <- ggplot(data=butts,
aes(x=Species, y=Butts.weight))+
ggtitle("Compare butts weight by species")+
xlab("Species")+ylab("Butts weight (g)")+
geom_point(position=position_jitter(w=0.2))+
geom_boxplot(notch=TRUE, alpha=0.2, outlier.size=0)
birdbox
ggsave(plot=birdbox, file='../../MyStuff/Images/bird-butts-mites-weight-ggplot-003.png',
h=4, w=6, units="in", dpi=300)
birdbox <- ggplot(data=butts,
aes(x=Species, y=log(Butts.weight)))+
ggtitle("Compare butts weight by species")+
xlab("Species")+ylab("log(Butts weight (g))")+
geom_point(position=position_jitter(w=0.2))+
geom_boxplot(notch=TRUE, alpha=0.2, outlier.size=0)
birdbox
ggsave(plot=birdbox, file='../../MyStuff/Images/bird-butts-mites-weight-ggplot-004.png',
h=4, w=6, units="in", dpi=300)
#----------------------------------------------------------------
# Bar charts and line charts with standard errors
#source("schwarz.functions.r")  # load some helper functions
source('http://www.stat.sfu.ca/~cschwarz/Stat-650/Notes/MyPrograms/schwarz.functions.r')
# Compute the mean calories/serving by fiber group with se and ci
sumstat.all <- sf.simple.summary(cereal, "calories", crd=TRUE)
sumstat.all
library(plyr)
sumstat.shelf <- ddply(cereal, "shelfF", sf.simple.summary,
variable="calories", crd=TRUE)
sumstat.shelf
# Side-by-side bar charts
cerealbar <- ggplot(data=sumstat.shelf, aes(x=shelfF, y=mean))+
ggtitle("Mean calories by shelf with 95% ci")+
xlab("Shelf")+ylab("Mean calories/serving with 95% ci")+
geom_bar(stat="identity", alpha=0.2)+
geom_errorbar(aes(ymin=lcl, ymax=ucl), width=0.2)
cerealbar
ggsave(cerealbar, file="../../MyStuff/Images/ggplot2-bar-cereal-001.png",
h=4, w=6, units="in", dpi=300)
# A line chart is similar, except you don't need to start
# the bars at zero
cerealline <- ggplot(data=sumstat.shelf, aes(x=shelfF, y=mean))+
ggtitle("Mean calories by shelf with 95% ci")+
xlab("Shelf")+ylab("Mean calories/serving with 95% ci")+
geom_line(aes(group=1))+
geom_errorbar(aes(ymin=lcl, ymax=ucl), width=0.2)
cerealline
ggsave(cerealline, file="../../MyStuff/Images/ggplot2-line-cereal-001.png",
h=4, w=6, units="in", dpi=300)
#----------------------------------------------------------------
# compare the mean butts.weight and number of mites by species/ contents
library(readxl)
butts <- readxl::read_excel('../sampledata/bird-butts-data.xlsx',
sheet='Correlational',
col_names=TRUE,
trim_ws = TRUE,
skip=1)
names(butts) <- make.names(names(butts))
names(butts)[ grepl('wieght', names(butts))] <- "Butts.weight"
butts$log.mites <- log(butts$Number.of.mites)
library(plyr)
sumstat <- ddply(butts, "Nest.content", sf.simple.summary,
variable="Number.of.mites", crd=TRUE)
sumstat$Nest.contentF <- factor(sumstat$Nest.content,
levels=c("empty","eggs","chicks"),
order=TRUE)
sumstat
# Side-by-side bar charts
nestbar <- ggplot(data=sumstat, aes(x=Nest.contentF, y=mean))+
ggtitle("Mean number of mites by nest content with 95% ci")+
xlab("Nest Content")+ylab("Mean number of mites with 95% ci")+
geom_bar(stat="identity", alpha=0.2)+
geom_errorbar(aes(ymin=lcl, ymax=ucl), width=0.2)
nestbar
ggsave(nestbar, file="../../MyStuff/Images/bird-butts-mites-weight-bar-ggplot-001.png",
h=4, w=6, units="in", dpi=300)
# A line chart is similar, except you don't need to start
# the bars at zero
nestline <- ggplot(data=sumstat, aes(x=Nest.contentF, y=mean))+
ggtitle("Mean number of mites by nest content with 95% ci")+
xlab("Nest Content")+ylab("Mean number of mites with 95% ci")+
geom_line(aes(group=1))+
geom_errorbar(aes(ymin=lcl, ymax=ucl), width=0.2)
nestline
ggsave(nestline, file="../../MyStuff/Images/bird-butts-mites-weight-line-ggplot-001.png",
h=4, w=6, units="in", dpi=300)
#----------------------------------------------------------------
# Facetting
#The data can be split up by one or two variables that vary on the horizontal and/or vertical direction.
#This is done by giving a formula to facet_grid(), of the form vertical ~ horizontal.
#
cerealplot <- ggplot(data=cereal, aes(x=fat, y=calories))+
ggtitle("Calories vs fat in each serving")+
xlab("fat/serving (g)")+ylab("calories/serving (g)")+
geom_point(position=position_jitter(width=0.1))+
geom_smooth(method="lm", se=FALSE)+
facet_wrap(~shelfF, ncol=2)
cerealplot
ggsave(cerealplot, file="../../MyStuff/Images/ggplot2-facet-cereal-001.png",
h=4, w=6, units="in", dpi=300)
# Plot the $\log(number~mites)$ vs.\ butts. weight with fitted line
# for each combination of species and nest content.
mitesfacet <- ggplot(data=butts, aes(x=Butts.weight, y=log.mites))+
ggtitle("Mean number of mites by butts weight")+
xlab("Butts weight (g)")+ylab("log(number of mites)")+
geom_point()+
geom_smooth(method="loess", se=FALSE)+
facet_grid(Species ~ Nest.content)
mitesfacet
ggsave(mitesfacet, file="../../MyStuff/Images/bird-butts-mites-weight-facet-ggplot-001.png",
h=4, w=6,  units="in", dpi=300)
# Use two variables in a facet definition
mitesfacet <- ggplot(data=butts, aes(x=Butts.weight, y=log.mites))+
ggtitle("Mean number of mites by butts weight")+
xlab("Butts weight (g)")+ylab("log(number of mites)")+
geom_point()+
geom_smooth(method="loess", se=FALSE)+
facet_wrap( ~Species + Nest.content, ncol=3)
mitesfacet
ggsave(mitesfacet, file="../../MyStuff/Images/bird-butts-mites-weight-facet-ggplot-002.png",
h=4, w=6,  units="in", dpi=300)
mitesfacet <- ggplot(data=butts, aes(x=Butts.weight, y=log.mites))+
ggtitle("Mean number of mites by butts weight")+
xlab("Butts weight (g)")+ylab("log(number of mites)")+
geom_point()+
geom_smooth(method="loess", se=FALSE)+
facet_wrap( ~Species + Nest.content, ncol=2)
mitesfacet
ggsave(mitesfacet, file="../../MyStuff/Images/bird-butts-mites-weight-facet-ggplot-003.png",
h=4, w=6,  units="in", dpi=300)
mitesfacet <- ggplot(data=butts, aes(x=Butts.weight, y=log.mites))+
ggtitle("Mean number of mites by butts weight")+
xlab("Butts weight (g)")+ylab("log(number of mites)")+
geom_point()+
geom_smooth(method="loess", se=FALSE)+
facet_wrap( ~Nest.content + Species, ncol=2)
mitesfacet
ggsave(mitesfacet, file="../../MyStuff/Images/bird-butts-mites-weight-facet-ggplot-004.png",
h=4, w=6,  units="in", dpi=300)
# Changing labels o facets
# See http://ggplot2.tidyverse.org/reference/labellers.html and
# https://stackoverflow.com/questions/3472980/ggplot-how-to-change-facet-labels
mitesfacet <- ggplot(data=butts, aes(x=Butts.weight, y=log.mites))+
ggtitle("Mean number of mites by butts weight")+
xlab("Butts weight (g)")+ylab("log(number of mites)")+
geom_point()+
geom_smooth(method="loess", se=FALSE)+
facet_wrap( ~Species + Nest.content, ncol=3, labeller=label_both)
mitesfacet
ggsave(mitesfacet, file="../../MyStuff/Images/bird-butts-mites-weight-facet-ggplot-005.png",
h=4, w=6,  units="in", dpi=300)
# changing what is printed in a facet
# Method 1: Create new variable using recode. But order of facets may change
cereal$shelf2 <- car::recode(cereal$shelf, "  1='low'; 2='medium'; 3='high'")
cerealplot <- ggplot(data=cereal, aes(x=fat, y=calories))+
ggtitle("Calories vs fat in each serving")+
xlab("fat/serving (g)")+ylab("calories/serving (g)")+
geom_point(position=position_jitter(width=0.1))+
geom_smooth(method="lm", se=FALSE)+
facet_wrap(~shelf2, ncol=3)
cerealplot
ggsave(cerealplot, file="../../MyStuff/Images/ggplot2-facet-cereal-002.png",
h=4, w=6, units="in", dpi=300)
# Method 2: Create factor variable with appropriate labels
cereal$shelfF2 <- factor(cereal$shelf, labels=c("low","medium","high"))
cerealplot <- ggplot(data=cereal, aes(x=fat, y=calories))+
ggtitle("Calories vs fat in each serving")+
xlab("fat/serving (g)")+ylab("calories/serving (g)")+
geom_point(position=position_jitter(width=0.1))+
geom_smooth(method="lm", se=FALSE)+
facet_wrap(~shelfF2, ncol=3)
cerealplot
ggsave(cerealplot, file="../../MyStuff/Images/ggplot2-facet-cereal-003.png",
h=4, w=6, units="in", dpi=300)
# Method 3: Use a labeller function
cereal$shelfc <- as.character(cereal$shelf)
shelf_names <- c('1' = "low",
'2' = "medium",
'3' = "high")
cerealplot <- ggplot(data=cereal, aes(x=fat, y=calories))+
ggtitle("Calories vs fat in each serving")+
xlab("fat/serving (g)")+ylab("calories/serving (g)")+
geom_point(position=position_jitter(width=0.1))+
geom_smooth(method="lm", se=FALSE)+
facet_wrap(~shelfc, ncol=3, labeller=labeller(shelfc=as_labeller(shelf_names)))
cerealplot
ggsave(cerealplot, file="../../MyStuff/Images/ggplot2-facet-cereal-004.png",
h=4, w=6, units="in", dpi=300)
# What happens if there is mismatch?
cereal$shelfc <- as.character(cereal$shelf)
shelf_names <- c('1' = "low",
'2' = "medium",
'4' = "high")
cerealplot <- ggplot(data=cereal, aes(x=fat, y=calories))+
ggtitle("Calories vs fat in each serving")+
xlab("fat/serving (g)")+ylab("calories/serving (g)")+
geom_point(position=position_jitter(width=0.1))+
geom_smooth(method="lm", se=FALSE)+
facet_wrap(~shelfc, ncol=3, labeller=labeller(shelfc=as_labeller(shelf_names)))
cerealplot
ggsave(cerealplot, file="../../MyStuff/Images/ggplot2-facet-cereal-005.png",
h=4, w=6, units="in", dpi=300)
# Very long tick mark labels
# Not sure why the recode doesn't work directly
cereal$shelf.special <- car::recode(cereal$shelf,
"1='Bottom\nShelf'; 2='Middle\nShelf'; 3='Top\nShelf'")
cereal$shelf.special <- gsub(" ", "\n", cereal$shelf.special)
cerealplot <- ggplot(data=cereal, aes(x=shelf.special, y=calories))+
ggtitle("Calories vs. shelf")+
xlab("fat/serving (g)")+ylab("calories/serving (g)")+
geom_point(position=position_jitter(width=0.1))+
geom_boxplot( alpha=0.2, outlier.size=0)
cerealplot
ggsave(cerealplot, file="../../MyStuff/Images/ggplot2-cereal-longtickmarks-001.png",
h=4, w=6, units="in", dpi=300)
# Rotat tick mark labels
cerealplot <- ggplot(data=cereal, aes(x=shelf.special, y=calories))+
ggtitle("Calories vs shelf")+
xlab("fat/serving (g)")+ylab("calories/serving (g)")+
geom_point(position=position_jitter(width=0.1))+
geom_boxplot( alpha=0.2, outlier.size=0)+
theme(axis.text.x = element_text(angle = 45, hjust = 1))
cerealplot
ggsave(cerealplot, file="../../MyStuff/Images/ggplot2-cereal-longtickmarks-002.png",
h=4, w=6, units="in", dpi=300)
#---------------------------------------------
# Other packages that are useful
# lm and glm() diagnostic plots
library(ggfortify)
lm.fit <- lm(calories ~ fat, data=cereal)
diagplot <- autoplot(lm.fit)
diagplot
ggsave(diagplot, file="../../MyStuff/Images/ggplot2-ggfortify-001.png",
h=4, w=6, units="in", dpi=300)
# scatter plot matrix
library(GGally)
spm <- ggpairs(cereal, col=c(3,4,5,6,7,8,9,10))
spm
ggsave(spm, file="../../MyStuff/Images/ggplot2-ggally-001.png",
h=4, w=6, units="in", dpi=300)
# plotting geographical data
library(ggmap)
sfu.coord <- c(-122.917957, 49.276765 )
my.drive.csv <- textConnection("
long, lat
-122.84378900000002, 49.29009199999999
-122.82799615332033, 49.28426960031931
-122.82696618505861, 49.27755059244836
-122.86679162451173, 49.27676664856581
-122.88790597387697, 49.26276555269492
-122.90833367773439, 49.26534205263451
-122.92532815405275, 49.273518748310764
-122.91434182592775, 49.27766258341439")
my.drive <- read.csv(my.drive.csv, header=TRUE, as.is=TRUE, strip.white=TRUE)
# get the map from google. You can fiddle with the zoom to get the right scale
#cc <- get_map(sfu.coord, maptype="terrain",  source="google")#zoom=13)
google.map <- get_map(sfu.coord, maptype="satellite",  source="google", zoom=12)
my.map <- ggmap(google.map)
plot1 <- my.map +
ggtitle("My drive to work")+
geom_point(data=my.drive, aes(x=long, y=lat),size=1, color='red' )+
geom_path(data=my.drive, aes(x=long, y=lat), color="red", size=2)+
ylab("Latitude")+xlab("Longitude")
plot1
ggsave(plot1, file="../../MyStuff/Images/ggplot2-ggmap-001.png",
h=4, w=6, units="in", dpi=300)
#---------- Multiple (different plots) on a page
library(gridExtra)
p1 <- ggplot(data=cereal, aes(x=fat, y=calories))+
ggtitle("Calories vs fat")+
geom_point()
p1
p2 <- ggplot(data=cereal, aes(x=calories))+
ggtitle("Histogram of calories")+
geom_histogram()
p2
p3 <- ggplot(data=cereal, aes(x=fat))+
ggtitle("Histogram of fat")+
geom_histogram()
p3
p4 <- ggplot(data=cereal, aes(x=shelf, y=calories))+
ggtitle("Box plot of calories")+
geom_boxplot()
p4
allplot <- arrangeGrob(p1,p2,p3,p4, nrow=2,
top="A medley of plots")
plot(allplot)
ggsave(plot=allplot, file="../../MyStuff/Images/ggplot2-arrangeGrob-001.png",
h=4, w=6, units="in", dpi=300)
# Or using GGally
library(GGally)
plot.list <- list(p1, p2, p3, p4)
allplot <- GGally::ggmatrix(plot.list,
ncol=2, nrow=2)
allplot
ggsave(plot=allplot, file="../../MyStuff/Images/ggplot2-ggally-ggmatrix-001.png",
h=6, w=6, units="in", dpi=300)
cereal2 <- readxl::read_excel('../SampleData/ALLofDATA.xls',
sheetName='cereal',
col_names=TRUE,
trim_ws=TRUE,
skip=7)
names(cereal2) <- make.names(names(cereals))
cereal2 <- readxl::read_excel('../SampleData/ALLofDATA.xls',
sheet='cereal',
col_names=TRUE,
trim_ws=TRUE,
skip=7)
names(cereal2) <- make.names(names(cereals))
names(cereal2) <- make.names(names(cereal2))
head(cereal2)
# Different ways to read in data
options(useFancyQuotes=FALSE) # renders summary output corrects
#source("schwarz.functions.r")
source('http://www.stat.sfu.ca/~cschwarz/Stat-650/Notes/MyPrograms/schwarz.functions.r')
# load required libraries
library(readxl)
library(readxl)
# Read in the cereal data from a csv file
cereal <- read.csv('../SampleData/cereal.csv',
header=TRUE, as.is=TRUE, strip.white=TRUE)
head(cereal)
str(cereal)
#-------------------------------------------------------
# Reading an Excel workbook
library(readxl)
cereal2 <- readxl::read_excel('../SampleData/ALLofDATA.xls',
sheet='cereal',
col_names=TRUE,
trim_ws=TRUE,
skip=7)
names(cereal2) <- make.names(names(cereal2))
head(cereal2)
str(cereal2)
#-------------------------------------------------------
# Reading white space delimited table from the Internet
cereal4 <- read.table("http://lib.stat.cmu.edu/datasets/1993.expo/cereal",
header=FALSE, as.is=TRUE, strip.white=TRUE)
names(cereal4) <- c('Name','mfr','type','Calories','protein','Fat','sodium','fiber','carbo',
'sugars','shelf','potass','vitamins','weight','cups')
head(cereal4)
str(cereal4)
# Reading small table stored with the script
type.code.csv <- textConnection("
type, code
C , Cold Cereal
H , Hot Cereal  ")
type.code <- read.csv(type.code.csv, header=TRUE, strip.white=FALSE, as.is=TRUE)
head(type.code)
str(type.code)
type.code$type == "C"
type.code$type
# oops forgot to strip white space
type.code.csv <- textConnection("
type, code
C , Cold Cereal
H , Hot Cereal  ")
type.code <- read.csv(type.code.csv, header=TRUE, strip.white=TRUE, as.is=TRUE)
head(type.code)
str(type.code)
type.code$type == "C"
type.code$type
#-------------------------------------------------------
# Correcting variable names
sample.csv <- textConnection("
Bird #, Wieght, Length mm, Mass (g)
1, 100, 101, 102
2, 200, 201, 202")
sample <- read.csv(sample.csv, header=TRUE,
strip.white=TRUE, as.is=TRUE)
head(sample)
str(sample)
sample$Bird..
sample.csv <- textConnection("
Bird #, Wieght, Length mm, Mass (g)
1, 100, 101, 102
2, 200, 201, 202")
sample <- read.csv(sample.csv, header=TRUE,
strip.white=TRUE, as.is=TRUE,
check.names=FALSE)
head(sample)
str(sample)
sample$Bird..
sample$"Bird #"
# Using the names function to convert variable names
sample2 <- sample
names(sample2)
names(sample2) <- c("Bird","Weight","Length","Mass")
head(sample2)
# you can access individual names, but this is fragile
# in case the order of the columns changes
sample2 <- sample
names(sample2)
names(sample2)[2] <- c("Weight")
head(sample2)
# you can access individual names through a selection process
# be paranoid about change
sample2 <- sample
names(sample2)
select <- grepl("Wieght", names(sample2))
select
sum(select)
names(sample2)[select]
names(sample2)[select] <- c("Weight")
head(sample2)
#-----------------------------------------------------------
# Exercise
library(readxl)
butts <- readxl::read_excel('../sampledata/bird-butts-data.xlsx',
sheet='Correlational',
col_names=TRUE,
trim_ws = TRUE,
skip=1)
names(butts) <- make.names(names(butts))
butts[1:5,]
dim(butts)
str(butts)
# Or, save the sheet from the Excel file and read the csv file
butts <- read.csv("../sampledata/bird-butts-data-correlational.csv", header=TRUE, skip=1, as.is=TRUE, strip.white=TRUE)
butts[1:5,]
dim(butts)
str(butts)
# Fix the names
select <-  grepl('wieght', names(butts))
select
sum(select)
names(butts)[select]
names(butts)[ select] <- "Butts.weight"
butts[1:5,]
setwd("~/Dropbox/Stat-R/CourseNotes/sampledata")
install.packages(c("BH", "checkmate", "clipr", "colorspace", "curl", "data.table", "dbplyr", "DHARMa", "e1071", "gbm", "gclus", "git2r", "glmmTMB", "GPfit", "htmlTable", "mgsub", "mitml", "openssl", "psych", "RcppArmadillo", "rlang", "rsconnect", "rstudioapi", "spatstat", "spData", "TH.data", "tibble", "tinytex"))
