I have a loop of 4 graphs with a character list like 'a, b, c, d', so in the title of each graph I want 'a', 'b', 'c' or 'd'. However, when I run my code, 'a' appears in all titles.
This is the dput of the data I am using.
structure(list(Point = c(5, 6, 7, 8), La = c(535, 565, 532, 587
), Ce = c(45, 46, 58, 43), Pr = c(56, 54, 43, 50), Nd = c(23,
28, 18, 26)), class = c("spec_tbl_df", "tbl_df", "tbl", "data.frame"
), row.names = c(NA, -4L), spec = structure(list(cols = list(
Point = structure(list(), class = c("collector_double", "collector"
)), La = structure(list(), class = c("collector_double",
"collector")), Ce = structure(list(), class = c("collector_double",
"collector")), Pr = structure(list(), class = c("collector_double",
"collector")), Nd = structure(list(), class = c("collector_double",
"collector"))), default = structure(list(), class = c("collector_guess",
"collector")), skip = 1), class = "col_spec"))
and the code I came up so far. ONLY the cols do not cycle through the title. The rest of the code works perfectly. I am still a beginner, so thank you for your time and patience.
acq <- select(X1, La:Nd)
##loop##
gg <- for (ii in acq){
cols <- names(X1)[2:5]
m <-mean(ii)
sds <- sd(ii)
m1 <- mean(ii)+1
m2 <-mean(ii)-1
##plot##
g <- ggplot(X1,aes_string(x="Point",y="ii")) +
ggtitle(paste(cols,"\n",m,"\n",sds,"\n")) +
theme(plot.title = element_text(hjust = 0.5)) +
geom_line() + geom_hline(aes(yintercept=mean(ii))) + ylab('') + xlab('')+
geom_hline(aes(yintercept=m1),linetype=2) +
geom_text(x=8,y=m1,label="10%",vjust=-1) +
geom_hline(aes(yintercept=m2),linetype=2) +
geom_text(x=8,y=m2,label="10%",vjust=-1)
print(g)
}
My data:
~Point, ~La, ~Ce, ~Pr, ~Nd,
5, 535, 45, 56, 23,
6, 565, 46, 54, 28,
7, 532, 58, 43, 18,
8, 587, 43, 50, 26
They way you setup the for-loop is not really recommended. It's better to loop through column names then extract that column from the acq data frame accordingly
library(tidyverse)
acq <- select(X1, La:Nd)
## loop ##
for (ii in seq_along(colnames(acq))) {
current_col <- colnames(acq)[ii]
print(paste0('Plot col: ', current_col))
# calculate mean and stdev
m <- mean(acq[[current_col]])
sds <- sd(acq[[current_col]])
m1 <- m + 1
m2 <- m - 1
## plot ##
g <- ggplot(X1, aes_string(x = "Point", y = current_col)) +
ggtitle(paste("column = ", current_col, "\n",
"mean = ", formatC(m, digits = 3), "\n",
"sd = ", formatC(sds, digits = 3), "\n")) +
theme_classic(base_size = 12) +
theme(plot.title = element_text(hjust = 0.5)) +
geom_line() +
geom_hline(aes(yintercept = m)) +
ylab("") + xlab("") +
geom_hline(aes(yintercept = m1), linetype = 2) +
geom_text(x = 8, y = m1, label = "10%", vjust = -1, check_overlap = TRUE) +
geom_hline(aes(yintercept = m2), linetype = 2) +
geom_text(x = 8, y = m2, label = "10%", vjust = 2, check_overlap = TRUE)
print(g)
}
Example output:
#> [1] "Plot col: La"
#> [1] "Plot col: Ce"
Another (preferable) way is to use the new tidy evaluation approach (more explanation here)
generate_plot2 <- function(df, .x.variable, .y.variable) {
x.variable <- rlang::sym(.x.variable)
y.variable <- rlang::sym(.y.variable)
sum_df <- df %>%
summarise_at(vars(!!y.variable), funs(mean, sd)) %>%
mutate(m1 = mean + 1,
m2 = mean - 1)
print(sum_df)
g <- ggplot(df, aes(x = !! x.variable, y = !! y.variable)) +
ggtitle(paste("column = ", .y.variable, "\n",
"mean = ", formatC(sum_df$mean, digits = 3), "\n",
"sd = ", formatC(sum_df$sd, digits = 3), "\n")) +
geom_line() +
geom_hline(aes(yintercept = sum_df$mean)) +
ylab("") + xlab("") +
geom_hline(aes(yintercept = sum_df$m1), linetype = 2) +
geom_text(x = 8, y = sum_df$m1, label = "10%", vjust = -1, check_overlap = TRUE) +
geom_hline(aes(yintercept = sum_df$m2), linetype = 2) +
geom_text(x = 8, y = sum_df$m2, label = "10%", vjust = 2, check_overlap = TRUE) +
theme_classic(base_size = 12) +
theme(plot.title = element_text(hjust = 0.5))
return(g)
}
plot_list <- names(X1)[-1] %>%
map(~ generate_plot2(X1, "Point", .x))
#> mean sd m1 m2
#> 1 554.75 26.15817 555.75 553.75
#> mean sd m1 m2
#> 1 48 6.78233 49 47
#> mean sd m1 m2
#> 1 50.75 5.737305 51.75 49.75
#> mean sd m1 m2
#> 1 23.75 4.349329 24.75 22.75
plot_list[[1]]
plot_list[[2]]
# bonus: combine all plots
library(cowplot)
plot_grid(plotlist = plot_list,
labels = 'AUTO',
nrow = 2,
align = 'hv',
axis = 'tblr')
Created on 2019-03-16 by the reprex package (v0.2.1.9000)
Related
I want to make a multiple-line plot in `facet_grid like this:
I have the following R code that draws column bar plots in the facet grid
library(ggplot2)
library(reshape2)
set.seed(199)
MB_RMSE_sd1 <- runif(12, min = 0, max = 2)
TMB_RMSE_sd1 <- runif(12, min = 0, max = 2)
MB_RMSE_sd3 <- runif(12, min = 2, max = 5)
TMB_RMSE_sd3 <- runif(12, min = 2, max = 5)
MB_RMSE_sd5 <- runif(12, min = 5, max = 10)
TMB_RMSE_sd5 <- runif(12, min = 5, max = 10)
MB_RMSE_sd10 <- runif(12, min = 7, max = 16)
TMB_RMSE_sd10 <- runif(12, min = 7, max = 16)
ID <- rep(rep(c("N10_AR0.8", "N10_AR0.9", "N10_AR0.95", "N15_AR0.8", "N15_AR0.9", "N15_AR0.95", "N20_AR0.8", "N20_AR0.9", "N20_AR0.95", "N25_AR0.8", "N25_AR0.9", "N25_AR0.95"), 2), 1)
df1 <- data.frame(ID, MB_RMSE_sd1, MB_RMSE_sd3, MB_RMSE_sd5, MB_RMSE_sd10, TMB_RMSE_sd1, TMB_RMSE_sd3, TMB_RMSE_sd5, TMB_RMSE_sd10)
reshapp1 <- reshape2::melt(df1, id = "ID")
NEWDAT <- data.frame(value = reshapp1$value, year = reshapp1$ID, n = rep(rep(c("10", "15", "20", "25"), each = 3), 16), Colour = rep(rep(c("RMSE_MB", "RMSE_TMB"), each = 12), 4), sd = rep(rep(c(1, 3, 5, 10), each = 48), 1), phi = rep(rep(c("0.8", "0.9", "0.95"), 16), 4))
NEWDAT$sd <- with(NEWDAT, factor(sd, levels = sd, labels = paste("sd =", sd)))
NEWDAT$year <- factor(NEWDAT$year, levels = NEWDAT$year[1:12])
NEWDAT$n <- with(NEWDAT, factor(n, levels = n, labels = paste("n = ", n)))
library(ggpattern)
ggplot() +
geom_col_pattern(
data = NEWDAT[NEWDAT$Colour %in% c("RMSE_MB", "RMSE_TMB"), ],
aes(x = phi, y = value, pattern = rev(Colour), pattern_angle = rev(Colour)),
fill = 'white',
colour = 'black',
pattern_density = 0.1,
pattern_fill = 'black',
pattern_colour = 'black'
) +
facet_grid(sd ~ n, scales = "free") +
scale_fill_manual(
breaks = c("RMSE_MB", "RMSE_TMB"),
values = c("red", "blue", "orange", "green")
) +
scale_y_continuous(expand = c(0, 0), label = ~ abs(.)) +
guides(fill = guide_legend(reverse = TRUE)) +
labs(fill = "") +
theme_bw() +
theme(axis.text.x = element_text(angle = -90, vjust = 0.5))
#ggsave("AR1.pdf", height = 8, width = 7, device = "pdf", dpi = 700)
EDIT1
What I have after using the answer below:
library(ggplot2)
library(reshape2)
set.seed(199)
MB_RMSE_sd1 <- runif(12, min = 0, max = 2)
TMB_RMSE_sd1 <- runif(12, min = 0, max = 2)
MB_RMSE_sd3 <- runif(12, min = 2, max = 5)
TMB_RMSE_sd3 <- runif(12, min = 2, max = 5)
MB_RMSE_sd5 <- runif(12, min = 5, max = 10)
TMB_RMSE_sd5 <- runif(12, min = 5, max = 10)
MB_RMSE_sd10 <- runif(12, min = 7, max = 16)
TMB_RMSE_sd10 <- runif(12, min = 7, max = 16)
ID <- rep(rep(c("N10_AR0.8", "N10_AR0.9", "N10_AR0.95", "N15_AR0.8", "N15_AR0.9", "N15_AR0.95", "N20_AR0.8", "N20_AR0.9", "N20_AR0.95", "N25_AR0.8", "N25_AR0.9", "N25_AR0.95"), 1), 1)
df1 <- data.frame(ID, MB_RMSE_sd1, MB_RMSE_sd3, MB_RMSE_sd5, MB_RMSE_sd10, TMB_RMSE_sd1, TMB_RMSE_sd3, TMB_RMSE_sd5, TMB_RMSE_sd10)
reshapp1 <- reshape2::melt(df1, id = "ID")
NEWDAT <- data.frame(value = reshapp1$value, year = reshapp1$ID, n =
rep(rep(c("10", "15", "20", "25"), each = 3), 16), Colour =
rep(rep(c("RMSE_MB", "RMSE_TMB"), each = 3), 16), sd = rep(rep(c(1, 3, 5, 10), each = 24), 1), phi = rep(rep(c("0.8", "0.9", "0.95"), 16), 4))
NEWDAT$sd <- with(NEWDAT, factor(sd, levels = sd, labels = paste("sd =", sd)))
NEWDAT$year <- factor(NEWDAT$year, levels = NEWDAT$year[1:12])
NEWDAT$n <- with(NEWDAT, factor(n, levels = n, labels = paste("n = ", n)))
ggplot(NEWDAT, aes(phi, value)) +
geom_line(aes(linetype = Colour)) + geom_point() +
scale_y_continuous(expand = c(0, 0), label = ~ abs(.)) +
guides(fill = guide_legend(reverse = TRUE)) +
#labs(fill = "") +
facet_grid(sd ~ n, scales = "free") +
theme_bw() +
theme(axis.text.x = element_text(angle = -90, vjust = 0.5))
which produces this
WHAT I WANT
Here is a solution.
After reshaping the data, remove the duplicates with unique. Then the plot is easy, map the colour to linetype and the two lines shall be automatically separated.
library(ggplot2)
library(reshape2)
reshapp1 <- reshape2::melt(df1, id = "ID")
reshapp1 <- unique(reshapp1)
NEWDAT <- data.frame(value = reshapp1$value, year = reshapp1$ID,
n = rep(rep(c("10", "15", "20", "25"), each = 3), 16),
Colour = rep(rep(c("RMSE_MB", "RMSE_TMB"), each = 12), 4),
sd = rep(rep(c(1, 3, 5, 10), each = 48), 1),
phi = rep(rep(c(0.8, 0.9, 0.95), 16), 4))
NEWDAT$sd <- with(NEWDAT, factor(sd, levels = sd, labels = paste("sd =", sd)))
NEWDAT$year <- factor(NEWDAT$year, levels = NEWDAT$year[1:12])
NEWDAT$n <- with(NEWDAT, factor(n, levels = n, labels = paste("n = ", n)))
ggplot(NEWDAT, aes(phi, value)) +
geom_line(aes(linetype = Colour)) +
scale_y_continuous(expand = c(0, 0), label = ~ abs(.)) +
guides(fill = guide_legend(reverse = TRUE)) +
#labs(fill = "") +
facet_grid(sd ~ n, scales = "free") +
theme_bw() +
theme(axis.text.x = element_text(angle = -90, vjust = 0.5))
#ggsave("AR1.pdf", height = 8, width = 7, device = "pdf", dpi = 700)
Created on 2022-09-03 by the reprex package (v2.0.1)
I'd like to display the sample size of each species on my boxplot, but the plot is fairly cluttered. Is there a way to display the sample size on the "outside" of the plot with "N" as the header (sample size should go in the red area I highlighted)?
df <- data.frame(year = rep(c(2019, 2020), each = 10),
month = rep(c("March", "October"), each = 1),
site = rep(c("1", "2", "3", "4", "5"), each = 2),
type = rep(c("baitfish", "shark"), each = 1),
salinity = sample(x = 20:35, size = 20, replace = TRUE),
num = sample(x = 0:10, size = 20, replace = TRUE))
count_by_row <- data.frame(df[rep(row.names(df), df$num), 1:5])
ggplot(data=subset(count_by_row, !is.na(salinity)), aes(x = reorder(type, -salinity, FUN = median), y = salinity)) +
geom_boxplot(outlier.shape = 1, outlier.size = 2) +
coord_flip() +
xlab("") +
ylab("salinity (PSU)")
You could add a custom annotation after increasing the right margin:
ggplot(data=subset(count_by_row, !is.na(salinity)),
aes(y = reorder(type, -salinity, FUN = median), x = salinity)) +
geom_boxplot(outlier.shape = 1, outlier.size = 2, orientation = "y") +
coord_cartesian(clip = "off") +
annotation_custom(grid::textGrob(c("N", table(count_by_row$type)),
x = 1.1, y = c(0.9, 0.28, 0.72),
gp = grid::gpar(cex = 1.5))) +
ylab("") +
xlab("salinity (PSU)") +
theme_bw(base_size = 20) +
theme(plot.margin = margin(20, 100, 20, 20))
The dput(Q_Sheet) is below. How can properly introduce a second y-axis that is different in scale from the primary axis?
structure(list(Amino_acids = c(4, 12, 20, 28, 32), Protein_length_Ang = c(7,
24, 40, 56, 64), length_no_ratio = c(1.75, 2, 2, 2, 2), Corrected_aa = c(1.24459201924769e-12,
3.71007650662474e-09, 1.10594599229843e-05, 0.0319159404863842,
0.642857142857143), aa_frequency = c(3.99735380592756, 6.96840672963299,
4.58228895300999, 3.12310921028256, 4.67560843680985), T_degC = c(50.3857804818545,
52.8464583426248, 60.0760389538482, 58.1895053328481, 67.628202708438
)), row.names = c(NA, -5L), class = c("tbl_df", "tbl", "data.frame"
), na.action = structure(c(`2` = 2L, `4` = 4L, `6` = 6L), class = "omit"))
`
ggplot(data = Q_Sheet, aes(x = T_degC))+
geom_line(aes(y = Amino_acids), color="red")+
geom_line(aes(y = Corrected_aa), color = "blue") +
scale_y_continuous(name = "Amino_acids", sec.axis = sec_axis(~.*10, name = "Corrected_aa"))
The output is as follows:
<ScaleContinuousPosition>
Range:
Limits: 0 -- 1
You can use the below formula to keep the secondary Y-axis at the same level as Corrected_aa.
library(ggplot2)
ggplot(data=Q_Sheet, aes(x=T_degC))+
geom_line(aes(y=Amino_acids),color="red")+
geom_line(aes(y=Corrected_aa),color="blue")+
scale_y_continuous(name="Amino_acids",
sec.axis=sec_axis(~{
a <- min(Q_Sheet$Corrected_aa)
b <- max(Q_Sheet$Corrected_aa)
((((b-a) * (. - min(.)))/diff(range(.))) + a)
},name="Corrected_aa"))
There are two issues - 1) scale_y_continuous typo and 2) there is a missing + connecting the last expression
ggplot(data=Q_Sheet, aes(x=T_degC))+
geom_line(aes(y=Amino_acids),color="red")+
geom_line(aes(y=Corrected_aa),color="blue") +
scale_y_continuous(name="Amino_acids",
sec.axis=sec_axis(~.*10,name="Corrected_aa"))
-ouptut
We could define a coefficient and then color the lines to indicate wich lines belongs to which y-scale:
library(ggplot2)
value used to transform the data
coeff <- 0.01
# colors
Amino_acidsColor = "red"
Corrected_aaColor = "blue"
ggplot(data=Q_Sheet, aes(x=T_degC))+
geom_line(aes(y=Amino_acids), size = 2, color=Amino_acidsColor)+
geom_line(aes(y=Corrected_aa/coeff), size = 2, color=Corrected_aaColor) +
scale_y_continuous(name="Amino_acids",
sec.axis=sec_axis(~.*coeff,name="Corrected_aa")) +
theme_bw() +
theme(
axis.title.y = element_text(color = Amino_acidsColor, size=13),
axis.title.y.right = element_text(color = Corrected_aaColor, size=13)
)
I want to plot a bar like below.
Here is where I am.
attitude <- c('solid_blue', 'leaning_blue', 'toss_up', 'leaning_red', 'solid_red')
n_votes <- c(190, 108, 121, 39, 80)
group <- c(1,1,1,1,1)
df <- rbind(attitude, n_votes, group)
df <- as.data.frame(t(df))
ggplot(data = df) +
geom_bar(stat = 'identity', mapping = aes (x = group, y = n_votes, fill = attitude)) + coord_flip()
where df is like
attitude n_votes group
1 solid_blue 190 1
2 leaning_blue 108 1
3 toss_up 121 1
4 leaning_red 39 1
5 solid_red 80 1
I got a plot like this
The n_votes does not seem to accumulate correctly, how can I correct this?
Now I have this
Dan
Your main problem is because of the way you constructed your data frame, all the columns in it are character vectors. Look:
class(df$n_votes)
#> [1] "character"
It takes less code and gets better results to construct the data frame like this:
attitude <- c('solid_blue', 'leaning_blue', 'toss_up', 'leaning_red', 'solid_red')
n_votes <- c(190, 108, 121, 39, 80)
df <- data.frame(attitude, n_votes, group)
Now using your plot code (except noting that geom_bar(stat = "identity" is a long-hand way of writing geom_col(
ggplot(data = df) +
geom_col(aes(x = group, y = n_votes, fill = attitude)) +
coord_flip()
We get:
Or, if you want to get closer:
attitude <- c('solid_blue', 'leaning_blue', 'toss_up', 'leaning_red', 'solid_red')
n_votes <- c(190, 108, 121, 39, 80)
df <- data.frame(rev(attitude), rev(n_votes), group)
df$attitude <- factor(rev(attitude), levels = attitude)
ggplot(data = df) +
geom_col(aes(x = group, y = n_votes, fill = attitude)) +
scale_fill_manual(values = rev(c("#2558b1", "#77b3dd", "#cbcbcb", "#f3b0a7", "#d95551")),
guide = guide_none()) +
geom_text(check_overlap = TRUE, label = 298, size = 15,
x = 1.8, y = 0, hjust = 0, color = "#2558b1") +
geom_text(check_overlap = TRUE, label = 119, size = 15,
x = 1.8, y = sum(n_votes), hjust = 1, color = "#d95551") +
geom_text(check_overlap = TRUE, label = "Joe Biden\nDEMOCRAT",
size = 5, x = 1.8, y = 60, hjust = 0) +
geom_text(check_overlap = TRUE, label = "Donald J Trump\nREPUBLICAN",
size = 5, x = 1.8, y = sum(n_votes) - 60, hjust = 1) +
geom_text(check_overlap = TRUE, aes(x = group, y = n_votes, label = n_votes),
position = position_stack(vjust = 0.5), size = 5, color = "white") +
geom_segment(aes(x = 0.55, xend = 1.45, y = sum(n_votes)/2, yend = sum(n_votes)/2),
linetype = 2) +
coord_flip() +
theme_classic() +
scale_x_discrete(expand = expansion(add = c(0.7, 0.7))) +
theme(panel.background = element_rect(fill = "#fdf1e5"),
plot.margin = margin(50, 10, 50, 10),
axis.line = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
axis.text = element_blank())
I have got this data set and want to generate a sunburst plot. The data is of 4 columns which are unit, weight, year16 and year17. The sunburst is based on the values in the weight column. The code is there and when adding the coding for the third layer it is giving me an error. I think the error is coming when I am adding the third layer.
library("ggnewscale")
library(ggplot2)
#read file
weight.eg = read.csv("Dummy Data.csv", header = FALSE, sep =
";",encoding = "UTF-8")
#change column names
colnames(weight.eg) <- c
("unit","weight","year16","year17")
#check the class
sapply(weight.eg, class)
#View(weight.eg)
#as weight column is factor change into integer
weight.eg$weight = as.numeric(levels(weight.eg$weight))
[as.integer(weight.eg$weight)]
weight.eg$year16 = as.numeric(levels(weight.eg$year16))
[as.integer(weight.eg$year16)]
weight.eg$year17 = as.numeric(levels(weight.eg$year17))
[as.integer(weight.eg$year17)]
#Nas are introduced, remove
weight.eg <- na.omit(weight.eg)
#Sum of the total weight
sum_total_weight = sum(weight.eg$weight)
#First layer
firstLevel = weight.eg %>% summarize(total_weight=sum(weight))
cs_fun <- function(x){(cumsum(x) + c(0, cumsum(head(x , -1))))/ 2}
ggplot(weight.eg) +
geom_col(data = firstLevel,
aes(x = 1, y = total_weight)) +
geom_text(data = firstLevel,
aes(x = 1, y = total_weight / 2,
label = paste("Total Weight:", total_weight)),
colour = "black") +
geom_col(aes(x = 2,
y = weight, fill = weight),
colour = "black", size = 0.6) +
scale_fill_gradient(name = "Weight",
low = "white", high = "lightblue") +
# Open up new fill scale for next ring
new_scale_fill() +
geom_text(aes(x = 2, y = cs_fun(weight),
label = paste(unit, weight))) +
geom_col(aes(x = 3, y = weight, fill = year16),
size = 0.6, colour = "black") +
scale_fill_gradient(name = "Year16",
low = "red", high = "green") +
geom_text(aes(label = paste0(unit,year16), x = 3,
y = cs_fun(weight))) +
#next ring
new_scale_fill() +
geom_text(aes(x = 2, y = cs_fun(weight),
label = paste(unit, weight))) +
geom_col(aes(x = 4, y = weight, fill = year17),
size = 0.6, colour = "black") +
scale_fill_gradient(name = "Year17",
low = "red", high = "green") +
geom_text(aes(label = paste0(unit,year17), x = 4,
y = cs_fun(weight))) +
coord_polar(theta = "y")
The output for dput(weight.eg) is
structure(list(unit = structure(1:6, .Label = c("A", "B", "C",
"D", "E", "F", "Unit"), class = "factor"), weight = c(30, 25,
10, 17, 5, 13), year16 = c(70, 80, 50, 30, 60, 40), year17 = c(50,
100, 20, 30, 70, 60)), .Names = c("unit", "weight", "year16",
"year17"), row.names = 2:7, class = "data.frame", na.action =
structure(1L, .Names = "1", class = "omit"))
I want to include year17 as well and in the future there will be
columns, so that has to be added as well. Because of the error I
am not able to figure out what is wrong.