Creating multiple graphs based upon the column names - r

This is my first question on stackoverlow, please correct me if I am not following correct question protocols.
I am trying to create some graphs for data that has been collected over three time points (time 1, time 2, time 3) which equates to X1..., X2... and X3... at the beginning of column names. The graphs are also separated by the column $Group from the data frame.
I have no problem creating the graphs, I just have many variables (~170) and am wanting to compare time 1 vs time 2, time 2 vs time 3, etc. so am trying to work a shortcut to be running this kind of code rather than having to type out each one individually.
As indicated above, I have created variable names like X1... X2... which indicate the time that the variable was recorded i.e. X1BCSTCAT = time 1; X2BCSTCAT = time 2; X3BCSTCAT = time 3. Here is a small sample of what my data looks like:
df <- structure(list(ID = structure(1:6, .Label = c("101","102","103","118","119","120"), class = "factor"),
Group = structure(c(1L,1L,1L,2L,2L,2L), .Label = c("C8","TC"), class = "factor"),
Wave = structure(c(1L, 2L, 3L, 4L, 1L, 2L), .Label = c("A","B","C","D"), class = "factor"),
Yr = structure(c(1L, 2L, 1L, 2L, 1L, 2L), .Label = c("3","5"), class = c("ordered", "factor")),
Age.Yr. = c(10.936,10.936, 9.311, 10.881, 10.683, 11.244),
Training..hr. = c(10.667,10.333, 10.667, 10.333, 10.333, 10.333),
X1BCSTCAT = c(-0.156,0.637,-1.133,0.637,2.189,1.229),
X1BCSTCR = c(0.484,0.192, -1.309, 0.912, 1.902, 0.484),
X1BCSTPR = c(-1.773,0.859, 0.859, 0.12, -1.111, 0.12),
X2BCSTCAT = c(1.006, -0.379,-1.902, 0.444, 2.074, 1.006),
X2BCSTCR = c(0.405, -0.457,-1.622, 1.368, 1.981, 0.168),
X2BCSTPR = c(-0.511, -0.036,2.189, -0.036, -0.894, 0.949),
X3BCSTCAT = c(1.18, -1.399,-1.399, 1.18, 1.18, 1.18),
X3BCSTCR = c(0.967, -1.622, -1.622,0.967, 0.967, 1.255),
X3BCSTPR = c(-1.282, -1.282, 1.539,1.539, 0.792, 0.792)),
row.names = c(1L, 2L, 3L, 4L, 5L,8L), class = "data.frame")
Here is some working code to create one graph using ggplot for time 1 vs time 2 data on one variable:
library(ggplot2)
p <- ggplot(df, aes(x=df$X1BCSTCAT, y=df$X2BCSTCAT, shape = df$Group, color = df$Group)) +
geom_point() + geom_smooth(method=lm, aes(fill=df$Group), fullrange = TRUE) +
labs(title="BCSTCAT", x="Time 1", y = "Time 2") +
scale_color_manual(name = "Group",labels = c("C8","TC"),values = c("blue", "red")) +
scale_shape_manual(name = "Group",labels = c("C8","TC"),values = c(16, 17)) +
scale_fill_manual(name = "Group",labels = c("C8", "TC"),values = c("light blue", "pink"))
So I am really trying to create some kind of a shortcut where R will cycle through and match up variable names X1... vs X2... and so on and create the graphs. I assume there must be some way to plot either based upon matching column numbers e.g. df[,7] vs df[,10] and iterating through this process or plotting by actually matching the names (where the only difference in variable names is the number which indicates time).
I have previously cycled through creating individual graphs using the lapply function, but have no idea where to even start with trying to do this one.

A solution using tidyeval approach. We will need ggplot2 v3.0.0 (remember to restart your R session)
install.packages("ggplot2", dependencies = TRUE)
First we build a function that takes column and group names as inputs. Note the use of rlang::sym, rlang::quo_name & !!.
Then create 2 name vectors for x- & y- values so that we can loop through them simultaneously using purrr::map2.
library(rlang)
library(tidyverse)
df <- structure(list(ID = structure(1:6, .Label = c("101","102","103","118","119","120"), class = "factor"),
Group = structure(c(1L,1L,1L,2L,2L,2L), .Label = c("C8","TC"), class = "factor"),
Wave = structure(c(1L, 2L, 3L, 4L, 1L, 2L), .Label = c("A","B","C","D"), class = "factor"),
Yr = structure(c(1L, 2L, 1L, 2L, 1L, 2L), .Label = c("3","5"), class = c("ordered", "factor")),
Age.Yr. = c(10.936,10.936, 9.311, 10.881, 10.683, 11.244),
Training..hr. = c(10.667,10.333, 10.667, 10.333, 10.333, 10.333),
X1BCSTCAT = c(-0.156,0.637,-1.133,0.637,2.189,1.229),
X1BCSTCR = c(0.484,0.192, -1.309, 0.912, 1.902, 0.484),
X1BCSTPR = c(-1.773,0.859, 0.859, 0.12, -1.111, 0.12),
X2BCSTCAT = c(1.006, -0.379,-1.902, 0.444, 2.074, 1.006),
X2BCSTCR = c(0.405, -0.457,-1.622, 1.368, 1.981, 0.168),
X2BCSTPR = c(-0.511, -0.036,2.189, -0.036, -0.894, 0.949),
X3BCSTCAT = c(1.18, -1.399,-1.399, 1.18, 1.18, 1.18),
X3BCSTCR = c(0.967, -1.622, -1.622,0.967, 0.967, 1.255),
X3BCSTPR = c(-1.282, -1.282, 1.539,1.539, 0.792, 0.792)),
row.names = c(1L, 2L, 3L, 4L, 5L,8L), class = "data.frame")
# define a function that accept strings as input
pair_plot <- function(x_var, y_var, group_var) {
# convert strings to symbols
x_var <- rlang::sym(x_var)
y_var <- rlang::sym(y_var)
group_var <- rlang::sym(group_var)
# unquote symbols using !!
ggplot(df, aes(x = !! x_var, y = !! y_var, shape = !! group_var, color = !! group_var)) +
geom_point() + geom_smooth(method = lm, aes(fill = !! group_var), fullrange = TRUE) +
labs(title = "BCSTCAT", x = rlang::quo_name(x_var), y = rlang::quo_name(y_var)) +
scale_color_manual(name = "Group", labels = c("C8", "TC"), values = c("blue", "red")) +
scale_shape_manual(name = "Group", labels = c("C8", "TC"), values = c(16, 17)) +
scale_fill_manual(name = "Group", labels = c("C8", "TC"), values = c("light blue", "pink")) +
theme_bw()
}
# Test if the new function works
pair_plot("X1BCSTCAT", "X2BCSTCAT", "Group")
# Create 2 parallel lists
list_x <- colnames(df)[-c(1:6, (ncol(df)-2):(ncol(df)))]
list_x
#> [1] "X1BCSTCAT" "X1BCSTCR" "X1BCSTPR" "X2BCSTCAT" "X2BCSTCR" "X2BCSTPR"
list_y <- lead(colnames(df)[-(1:6)], 3)[1:length(list_x)]
list_y
#> [1] "X2BCSTCAT" "X2BCSTCR" "X2BCSTPR" "X3BCSTCAT" "X3BCSTCR" "X3BCSTPR"
# Loop through 2 lists simultaneously
# Supply inputs to pair_plot function using purrr::map2
map2(list_x, list_y, ~ pair_plot(.x, .y, "Group"))
Sample outputs:
#> [[1]]
#>
#> [[2]]
Created on 2018-05-24 by the reprex package (v0.2.0).

Related

Control order across factors in ggplot2

I have a plot that looks like below. I want to change the order so that the larger value comes first (so cyan would precede red). But I can't seem to do this. What am I doing wrong?
This is my current code block so far:
ggplot(df, aes(x = Gene.Set.Size, y = OR, label =P.value, color = Method, group = Method)) +
geom_point(position=position_dodge(width=0.5)) +
ggrepel::geom_text_repel(size = 6, box.padding = 1, segment.angle = 20, position=position_dodge(width=0.5))+
geom_pointrange(aes(ymax = UpperCI, ymin = LowerCI),position=position_dodge(width=0.5)) +
theme_bw() +
theme(text=element_text(size=25),axis.text.x = element_text(angle = 45, hjust = 1)) +
ylab("Odds ratio") +
xlab("Gene set size") +
theme(plot.margin = unit(c(2,2,2,2), "cm"))
> dput(df)
structure(list(Method = structure(c(1L, 1L, 1L, 2L, 2L, 2L), .Label = c("MAGMA",
"Pairwise"), class = "factor"), P.value = c(8.74e-28, 1.33e-56,
5.57e-92, 1.63e-44, 4.23e-71, 2.78e-95), OR = c(1.39, 1.424668,
1.4, 1.513, 1.478208, 1.409563), UpperCI = c(1.481491, 1.487065,
1.446039, 1.601557, 1.417117, 1.455425), LowerCI = c(1.316829,
1.364601, 1.356358, 1.42, 1.541768, 1.365056), Gene.Set.Size = structure(c(1L,
2L, 3L, 1L, 2L, 3L), .Label = c("500", "1000", "2000"), class = "factor")), row.names = c(NA,
-6L), class = "data.frame")
You must set the factor order.
library(ggplot2)
df <- structure(list(Method = structure(c(1L, 1L, 1L, 2L, 2L, 2L), .Label = c("MAGMA",
"Pairwise"), class = "factor"), P.value = c(8.74e-28, 1.33e-56,
5.57e-92, 1.63e-44, 4.23e-71, 2.78e-95), OR = c(1.39, 1.424668,
1.4, 1.513, 1.478208, 1.409563), UpperCI = c(1.481491, 1.487065,
1.446039, 1.601557, 1.417117, 1.455425), LowerCI = c(1.316829,
1.364601, 1.356358, 1.42, 1.541768, 1.365056), Gene.Set.Size = structure(c(1L,
2L, 3L, 1L, 2L, 3L), .Label = c("500", "1000", "2000"), class = "factor")), row.names = c(NA,
-6L), class = "data.frame")
#reorder Factor
df$Method = factor(df$Method, levels=c("Pairwise", "MAGMA"))
ggplot(df, aes(x=Gene.Set.Size, y=OR, label=P.value,
group= Method, color=Method)) +
geom_point(position=position_dodge(width=0.5)) +
ggrepel::geom_text_repel(size = 6, box.padding = 1, segment.angle = 20, position=position_dodge(width=0.5))+
geom_pointrange(aes(ymax = UpperCI, ymin = LowerCI),position=position_dodge(width=0.5)) +
theme_bw() +
theme(text=element_text(size=25),axis.text.x = element_text(angle = 45, hjust = 1)) +
ylab("Odds ratio") +
xlab("Gene set size") +
theme(plot.margin = unit(c(2,2,2,2), "cm"))
df %>% mutate(Method = fct_relevel(Method, 'Pairwise')) %>% <<your ggplot2 code>
should do the job, assuming you have imported the tidyverse pipe operator %>% and the forcats package, which you can do with require(tidyverse)
You can simply reverse the ordering of the Method factor with forcats::fct_rev.
df$Method <- fct_rev(df$Method)
Alternatively, you can specify the first level when you initially converted that column to a factor.

Graphing continuous data points using date and time in R

I am very new to RStudio so my coding is rudimentary.
I have a data set that contains six (6) columns: date5m, time5m, T5m, date28m, time28m, T28m. The data set is temperature data at two depths (5m and 28m) with an associate date and time stamp. My resulting graph appears to place all the data by day rather than a continuous display by the time that it was collected. Any assistance would be appreciated.
library(ggplot2)
library(scales)
library(dplyr)
Aberdeen <- read.csv(file.choose(), header = TRUE)
head(Aberdeen)
Aberdeen$ï..date5m = as.Date(Aberdeen$ï..date5m, format = "%Y-%m-%d")
Aberdeen$date28m = as.Date(Aberdeen$date28m, format = "%Y-%m-%d")
ggplot() + geom_point(data = Aberdeen, aes(x = ï..date5m, y = T5m),
colour = "darkgreen", size=0.25, na.rm=TRUE) +
geom_point(data = Aberdeen, aes(x = date28m, y = T28m), colour = "forestgreen", size=0.25, na.rm=TRUE) +
labs(x = "Date", y = "Temperature (\u00B0C)") +
ggtitle("Aberdeen") +
theme_bw() + theme(plot.title = element_text(hjust = 0.5)) +
scale_x_date(date_breaks = "month", labels=date_format("%b-%Y"))
I would like for the graph to display the data in a continuous fashion using both date and time stamp like this:
Here is the first 10 lines of my data set:
structure(list(date5m = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L), .Label = "2018-06-01", class = "factor"), time5m =
structure(1:10, .Label = c("14:40:30",
"14:42:34", "14:44:39", "14:46:40", "14:48:43", "14:50:46", "14:52:51",
"14:54:56", "14:56:59", "14:59:03"), class = "factor"), T5m = c(9.1,
9.02, 9, 9.12, 9.12, 9.1, 9.06, 9.02, 8.98, 9.02), date28m =
structure(c(1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), .Label = "2018-06-01", class =
"factor"),
time28m = structure(1:10, .Label = c("14:39:00", "14:49:00",
"14:59:00", "15:10:00", "15:20:00", "15:30:00", "15:40:00",
"15:50:00", "16:00:00", "16:11:00"), class = "factor"), T28m = c(1.93,
1.93, 1.93, 1.93, 1.93, 1.93, 1.93, 1.93, 1.93, 1.91)), row.names = c(NA,
10L), class = "data.frame")
This turned out to tricker than expected since the date and time columns are not consistent across the rows.
I had to manipulate the column names to provide a consistent separator in the name. I also combined the date and time columns into a single datetime object in order to plot properly.
Once the original data frame was converted from the original wide format into a long format the ggplot call was simplified.
"Aberdeen" is the name of the original dataframe from the read.csv statement (assume to match the sample data posted). Please see the code comments for additional details:
library(tidyr)
library(dplyr)
library(stringr)
#Rename the columns to add a '_' seperator between the letter and first number
#this is needed to make the separation and the pivot easier.
# See the tidyr pivot Vignette "Multiple observations per row"
names(Aberdeen) <- names(Aberdeen) %>% str_replace( "(\\D)(\\d)", "\\1_\\2")
#Adding a rownumber for tracking purposes
#Unite the date and time columns into 1 column
#reshape to long
dflong<-Aberdeen %>% mutate(rowid=row_number()) %>%
unite("datetime_5m", c(date_5m, time_5m)) %>%
unite("datetime_28m", c(date_28m, time_28m)) %>%
pivot_longer(cols= -rowid, names_to = c(".value", "depth"), names_sep="_")
#convert datetime column from character to datetime oject:
dflong$datetime<-as.POSIXct(dflong$datetime, "%Y-%m-%d_%H:%M:%S", tz="")
#plot grouping and coloring by the depth
ggplot(data = dflong, aes(x = datetime, y = T, group=depth, color=depth)) +
geom_point() +
labs(x = "Date", y = "Temperature (\u00B0C)") +
ggtitle("Aberdeen") +
theme_bw() + theme(plot.title = element_text(hjust = 0.5)) +
scale_x_datetime(date_breaks = "hour", labels=date_format("%b-%Y"))

Annotate faceted plot in ggplot2

I am working on the dataset reported here below (pre.sss)
pre.sss <- pre.sss <- structure(list(Pretest.num = c(63, 62, 61, 60, 59, 58, 57, 4,2, 1), stress = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 1L, 2L, 2L,1L), .Label = c("[0,6]", "(6,9]"), class = "factor"), time = c(1L,1L, 1L, 1L, 1L, 1L, 1L, 8L, 8L, 8L), after = structure(c(2L,2L, 2L, 2L, 2L, 2L, 1L, 1L, NA, 1L), .Label = c("no", "yes"), class = "factor"),id = c("call_fam", "call_fam", "call_fam", "call_fam", "call_fam","call_fam", "call_fam", "counselor", "counselor", "counselor")), .Names = c("Pretest.num", "stress", "time", "after","id"), reshapeLong = structure(list(varying = structure(list(after = c("after.call.fam", "after.speak", "after.send.email","after.send.card", "after.attend", "after.fam.mtg", "after.sup.grp","after.counselor")), .Names = "after", v.names = "after", times = 1:8),v.names = "after", idvar = "Pretest.num", timevar = "time"), .Names = c("varying","v.names", "idvar", "timevar")), row.names = c("63.1", "62.1","61.1", "60.1", "59.1", "58.1", "57.1", "4.8", "2.8", "1.8"), class = "data.frame")
and I need to plot the counts of several categorical variables according to a specific level of another categorical variable ('stress'): so, a faceted bobble-lot would do the job in my case
So what I do is the following:
ylabels = c('call_fam' = "call fam.member for condolences",
'speak' = "speak to fam.member in person",
'send.email' = "send condolence email to fam.member",
'send.card' = "send condolence card/letter to fam.member",
'attend' = "attend funeral/wake",
'fam.mtg' = "provide fam.meeting",
'sup.grp' = "suggest attending support grp.",
'counselor' = "make referral to bereavement counselor" )
p = ggplot(pre.sss, aes(x = after, y = id)) +
geom_count(alpha = 0.5, col = 'darkblue') +
scale_size(range = c(1,30)) +
theme(legend.position = 'none') +
xlab("Response") +
ylab("What did you do after learning about death?") +
scale_y_discrete(labels = ylabels) +
facet_grid(.~ pre.sss$stress, labeller = as_labeller(stress.labels))
and I obtain the following image, exactly as I want.
Now I would like to label each bubble with the count with which the corresponding data appear in the dataset.
dat = data.frame(ggplot_build(p)$data[[1]][, c('x', 'y', 'PANEL', 'n')])
dat$PANEL = ifelse(dat$PANEL==1, "[0,6]", "(6-9]")
colnames(dat) = c('x', 'y', 'stress', 'n')
p + geom_text(aes(x, y, label = n, group = NULL), data = dat)
This gives me the following error I really can't understand.
> p + geom_text(aes(x, y, label=n, group=NULL), data=dat)
Error in `$<-.data.frame`(`*tmp*`, "PANEL", value = c(1L, 1L, 1L, 1L, :
replacement has 504 rows, data has 46
Can anybody help me with this?
Thanks!
EM
The function you refer to as your labeller function is missing from this example still. geom_count uses stat_sum, which calculates a parameter n, the number of observations at that point. Because you can use this calculated parameter, you don't actually have to assign the plot to a variable and pull out its data, as you did with ggplot_build.
This should do what you're looking for:
ggplot(pre.sss, aes(x = after, y = id)) +
geom_count(alpha = 0.5, col = 'darkblue') +
# note the following line
stat_sum(mapping = aes(label = ..n..), geom = "text") +
scale_size(range = c(1,30)) +
theme(legend.position = 'none') +
xlab("Response") +
ylab("What did you do after learning about death?") +
scale_y_discrete(labels = ylabels) +
facet_grid(.~ stress)
The line I added computes the same thing as what's behind the scenes in geom_count, but gives it a text geom instead, with the label mapped to that computed parameter n.

Placing a point on a fitted geom_smooth

I have the following data.
> dput(testdat)
structure(list(Type = structure(c(2L, 2L, 2L, 2L, 2L, 2L), .Label = c("Saline",
"Compound1"), class = "factor"), Treatment = structure(c(1L,
2L, 3L, 4L, 6L, 5L), .Label = c(".0032uM", ".016uM", ".08uM",
".4uM", "2uM", "10uM"), class = "factor"), Peak = c(1071.28430020209,
1458.23366806524, 2714.49856342393, 3438.83453920159, 3938.86391759534,
2980.10159109856), Area1 = c(3312.99749863082, 4798.35142770291,
9044.21362002965, 11241.1497514069, 11575.3444645068, 9521.69011119236
), SS1 = c(781.759834505516, 1191.6273298958, 2180.02082601411,
2601.33855989239, 2492.11886600804, 2185.39715502702), Conc = c(0.0032,
0.016, 0.08, 0.4, 10, 2), logconc = c(-2.49485002168009, -1.79588001734408,
-1.09691001300806, -0.397940008672038, 1, 0.301029995663981),
Conc_nm = c(3.2, 16, 80, 400, 10000, 2000), logconc_nm = c(0.505149978319906,
1.20411998265592, 1.90308998699194, 2.60205999132796, 4,
3.30102999566398)), .Names = c("Type", "Treatment", "Peak",
"Area1", "SS1", "Conc", "logconc", "Conc_nm", "logconc_nm"), row.names = 2:7, class = "data.frame")
I've fitted the data (Peak) with a nls regression using the following code:
fit = nls(Peak ~ SSlogis(logconc_nm,Asym,xmid,scal),data=testdat)
This gives me a nice fit and I'm happy with it so I plot the dose response as follows:
m <- coef(fit)
vallog <- as.numeric(format((m[3]),dig=4))
val =round(10^val,2)
ggplot(data = testdat,aes(logconc_nm,Peak))+
geom_point()+
scale_x_log10(breaks=round(testdat$logconc_nm,2))+
geom_smooth(method = 'nls',
formula = y ~ SSfpl(x,A,B,xmid,scal),se=FALSE)+
geom_vline(color='red',xintercept = vallog,alpha=.5)+
geom_text(aes(x=vallog,y=max(Peak),label = paste0('EC50',val,'nM')),color='red')#,angle=90)
My Question is:
How can I add a big ol' red point on the blue line where the blue and red line meet. I'd like to replace the need for the red line with the red dot. I know i have to use geom_point but because it's a fitted line, i can't just say x=vallog can i?

Change x axis origin to a value (not zero) in ggplot2

I am working on generating a tornado plot in R. I am using ggplot2 package with code like the following:
dat <- structure(list(variable = structure(c(1L, 2L, 3L, 1L, 2L, 3L), .Label = c("# of nodes needed",
"# of nodes owned", "cost per node"), class = "factor"), Level = structure(c(2L,
2L, 2L, 1L, 1L, 1L), .Label = c("high", "low"), class = "factor"),
value = c(-275, -550, -50, 825, 275, 450)), .Names = c("variable",
"Level", "value"), row.names = c(NA, -6L), class = "data.frame")
ggplot(dat, aes(fill=Level,variable,value )) +
geom_bar(position = 'identity',stat = 'identity') + coord_flip()
I am curious as to how to change x-axis origin. Right now, the origin is automatically set to zero, and I want to be able to change it to a variable specified numeric value.
Not sure if you are still looking for an answer but I was just solving a similar problem. I used limitsand expand in scale_x_continuous.
So I guess for you it would look something like this:
ggplot(dat, aes(fill=Level,variable,value )) +
geom_bar(position = 'identity',stat = 'identity') +
scale_x_continuous(limits = c(2, 32), expand = c(0, 0))
except making limits = c(2,32) be whatever you want the limits of the x axis to be. Means you have to set this manually, but the best work around I came up with doing the same thing.

Resources