ggplot does not work if it is inside a for loop although it works outside of it
When in a for
loop, you have to explicitly print
your resulting ggplot
object :
for (i in 1:5) {
print(ggplot(df,aes(x,y))+geom_point())
}
ggplot2 panel populates with the wrong values when inside for loop
You can use aes_string
like this:
ggplot(iris) +
geom_point(aes_string(colnames(iris)[j], colnames(iris)[i], color = "Species"), shape=18, size=3.5) +
theme_light() +
theme(legend.position="none")
This also makes sure you don't have to use labs()
anymore.
This gives
Strange issue with ggplot inside a for-loop
As suggested in the comments. The issue was resolved as follows:
for (i in colnames(TS)[2:6]) {
assign(paste0("p",i),ggplot(TS, aes_string(x="Timestamp", y=i)) +
geom_line() +
scale_x_datetime(breaks = date_breaks("5 day")) +
theme_few())
}
p<-arrangeGrob(pT1,pT2,pT3,pT4,pT5,pT6)
ggsave("~/Desktop//TS.png",p)
Error on final object when generating ggplot objects in for loop with dplyr select()
The issue is that we cannot use get
to access dplyr
/tidyverse
data in a "programming" paradigm. Instead, we should use non standard evaluation to access the data. I offer a simplified function below (originally I thought it was a function masking issue as I quickly skimmed the question).
testfun <- function(df = df2, vars = letters[1:4]){
lapply(vars, function(y) {
ggplot(df,
aes(x = x, y = .data[[y]] )) +
geom_point() +
ylab(y)
})
}
Calling
plots <- testfun(df2)
plots[[1]]
EDIT
Since OP would like to know what the issue is, I have used a traditional loop as requested
testfun2 <- function(df = df2, vars = letters[1:4]){
## initialize list to store plots
plotlist <- list()
for (ll in vars){
## subset data
d_t <- df %>% select(x, ll) ## comment out select() to get working function
# print(data) ## uncomment to check that dataframe subset works correctly
## plot variable vs. x
p <- ggplot(d_t,
aes(x = x, y = .data[[ll]])) +
geom_point() +
ylab(ll)
## add plot to named list
plotlist[[ll]] <- p
## uncomment to see that each plot is being made
}
plotlist
}
pl <- testfun2(df2)
pl[[1]]
The reason get
does not work is that we need to use non-standard evaluation as the docs state. Related questions on using get may be useful.
First plot
An issue with tiff and ggplot R functions inside for loop
The solution was to envelop ggplot
function by base print
function in the loop:
print(ggplot(df_g_,aes(x=factor(g),fill=factor(O)))+geom_bar(stat="count")+xlab("")+labs(fill=''))
So, i've used the solution from the other post:
enter link description here
ggplot not ploting in a loop
Too long for a comment.
First, the convention on SO is that answers are reserved for reproducible code that demonstrates a solution. Anything less, like speculation or opinion, belongs in a comment. Since your code does not run at all as is (there is no my_data
), no one can answer you unless either you provide your data, or we create a sample for you. As you might expect, most people are justifiably unwilling to do the latter.
Second, this is not a good way to use ggplot
. The idea is to use aes(...)
to map the graph's aesthetics (e.g, x and y axis, colors, etc.) to columns of your dataset, using column names. So, something like this:
df = data.frame(time,
y1 = as.numeric(my_data[,i]),
y2 = as.numeric(my_data[,i+12]),
y3 = as.numeric(my_data[,i+24]))
p = ggplot(df, aes(x = time)) +
geom_line(aes(y=y1, colour="nr = 0.32")) +
geom_line(aes(y=y2, colour="nr = 0.4")) +
geom_line(aes(y=y3, colour="nr = 10")) +
...
would be better - although still not great.
Creating three lines using three calls to geom_line(...)
is not a good idea either. Probably a better way would be something like this:
library(reshape2)
df <- melt(data.frame(time,my_data[,i+c(0,12,24)]),
id.vars="time", variable.name="nr", value.name="y")
p = ggplot(df, aes(x = time, y=y, color=nr)) +
geom_line() +
scale_colour_manual("", labels=c("nr = 0.32", "nr = 0.4", "nr = 10"),
values = c("green", "royalblue4", "orangered"))+
...
This uses melt(...)
in the reshape2
package to convert the data from "wide" format (data for different lines in different columns), into "long" format (all the y-data in a single column, with a second column (nr
in the example) distinguishing the different lines. Now there's only one call to geom_line(...)
.
Pulling this altogether:
## create artificial data set to demonstrate solution
set.seed(1) # for reproducible example
my_data <- as.data.frame(matrix(rnorm(20*12*3), nrow=20))
library(reshape2)
library(ggplot2)
for (i in 1:12) {
df <- melt(data.frame(time,my_data[,i+c(0,12,24)]),id.vars="time", variable.name="nr", value.name="y")
p = ggplot(df, aes(x = time, y=y, color=nr)) +
geom_line() +
scale_colour_manual("", labels=c("nr = 0.32", "nr = 0.4", "nr = 10"),
values = c("green", "royalblue4", "orangered"))+
labs(x = "periodos", y = "vg4")+
ggtitle(paste0(title[i], "_vg4 for diff.nr - tax"))
plot_list[[i]] = p
print(p)
}
This produces 12 plots, the last of which is:
Finally, if you want to look at all the plots simultaneously, you can melt(...)
the full data set (all 12*3 = 36 columns) and use ggplot facets:
df <- melt(data.frame(time,my_data), id.vars="time", variable.name="nr", value.name="y")
df <- cbind(df,plot=rep(title,each=length(time)))
df$nr <- rep(c("A","B","C"),each=12*length(time))
ggplot(df, aes(x=time, y=y, color=nr))+
geom_line()+
facet_wrap(~plot, ncol=3)+
scale_colour_manual("", labels=c("nr = 0.32", "nr = 0.4", "nr = 10"),
values = c("green", "royalblue4", "orangered"))+
labs(x = "periodos", y = "vg4", title="vg4 for diff.nr - tax")
The result is a bit cramped in this tiny format, but a larger plot would be OK I suspect.
ggplot code works for a single list element for not in for loop
I have not checked out what exactly goes wrong with your for loop. However, in general I would suggest to put the plotting code inside a function if you want to make several plots using a loop. Makes the code much easier to read and to check.
Additionally my approach
Adds columns for the label and the colors based on your condition
ifelse(colA == "AA", ...
Uses a named color vector to make sure that colors are assigned to the right values
library(dplyr)
library(ggplot2)
# example data set:
df1 <- data.frame(
colA = c("AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ"),
colB = sample(1:100, 10),
colC = 1:10,
colD = c(22, 13, 13, 5, 4, 4, 3, 2, 2, 2),
colE = c("1.AA", "2.AB", "3.AC", "4.AD", "5.AE", "6.AF", "7.AG", "8.AH", "9.AI", "10.AJ")
)
df2 <- data.frame(
colA = c("BA", "AA", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ"),
colB = sample(1:100, 10),
colC = 1:10,
colD = c(13, 11, 8, 8, 6, 4, 4, 3, 2, 2),
colE = c("1.BA", "2.AA", "3.AC", "4.AD", "5.AE", "6.AF", "7.AG", "8.AH", "9.AI", "10.AJ")
)
df3 <- data.frame(
colA = c("CA", "CB", "AC", "AD", "AA", "AF", "AG", "AH", "AI", "AJ"),
colB = sample(1:100, 10),
colC = 1:10,
colD = c(13, 11, 8, 8, 6, 4, 4, 3, 2, 2),
colE = c("1.CA", "2.CB", "3.AC", "4.AD", "5.AA", "6.AF", "7.AG", "8.AH", "9.AI", "10.AJ")
)
toy_top_list <- list(df1, df2, df3)
names(toy_top_list) <- c("a", "b", "c")
toy_pie_list <- vector(mode = "list", length = length(toy_top_list))
plot_pie <- function(d, title) {
# Add colums with the colors and the labels
d <- d %>%
mutate(color = ifelse(colA == "AA", "red", "grey"),
label = ifelse(colA == "AA", paste0(colD, "%"), ""))
# Make a named vector of colors
slice_colors <- select(d, colE, color) %>%
tibble::deframe()
ggplot(d, aes(x = "", y = colD, fill = colE)) +
geom_col(col = "white", width = 2) +
scale_fill_manual(values = slice_colors, name = "colA") +
geom_text(aes(x = 1.3, label = label),
position = position_stack(vjust = 0.5),
col = "white", fontface = "bold"
) +
ggtitle(title) +
theme(
axis.title = element_blank(),
axis.ticks = element_blank(),
axis.text = element_blank(),
panel.grid = element_blank(),
panel.background = element_rect(fill = "white"),
plot.margin = unit(c(3, 1, 3, 1), "pt")
) +
coord_polar("y", direction = -1)
}
# for loop
for(i in names(toy_top_list)){
toy_pie_list[[i]] <- plot_pie(toy_top_list[[i]], i)
}
# or do it with lapply
toy_pie_list <- lapply(names(toy_top_list), function(x) plot_pie(toy_top_list[[x]], x))
# set names
toy_pie_list <- setNames(toy_pie_list, names(toy_top_list))
toy_pie_list$c
ggplot2 does not work in a function, but in outside it works
A function returns the object which is present in the last line of the function unless you have mentioned return
explicitly. In your function you have two if
condition. When aaa
is TRUE
it will go inside the if
function and then check for if (aaa==FALSE)
which is the next statement hence, the original ggplot
object is lost when aaa
is TRUE
Your function would work simply by replacing second if
with only else
. Also note that if your condition is already logical you don't need to check if(aaa==TRUE)
, only if (aaa)
would work.
So change the function to
foo <- function(aaa=TRUE) {
df<-data.frame(x=c(10,100,1000,10,100,1000),
y=c(1100,220000,33000000,1300,240000,36000000),
group=c("1","1","1","2","2","2"))
if (aaa) {
ggplot2::ggplot(df, aes(x = x, y = y, shape = group)) +
ggplot2::geom_line(position = position_dodge(0.2)) +
ggplot2::geom_point(position = position_dodge(0.2), size = 4)+
ggplot2::scale_y_log10()+
ggplot2::scale_x_log10()
}
else {
ggplot2::ggplot(df, aes(x = x, y = y, shape = group)) +
ggplot2::geom_line(position = position_dodge(0.2)) +
ggplot2::geom_point(position = position_dodge(0.2), size = 4) +
ggplot2::scale_y_log10()
}
}
For Loop In R not working with Plot function
You have to do two things to make it work in a for
loop.
(1) As @neilfws already points out in the comments, the output of the for
loop needs to be assiged (e.g. out[[i]] <-
).
(2) Since ggplot
uses lazy evaluation only doing (1) will yield the same plot forty times (always the last plot, i = 40
). If you want to stick to a for
loop instead of an lapply
you could wrap the function call into eval(bquote())
and evaluate .(i)
.
x <- 1:40
out <- vector("list", length = length(x))
for (i in x) {
out[[i]] <- eval(bquote(
showPrincipalComponents(comp[.(i)])
))
}
out
Related Topics
Convert Multiple Columns of Numeric Data to Dates in R
How to Append a Sequential Number for Every Element in a Data Frame
Create and Assign Multiple New Dataframe Columns in Ifelse Statement
Ggplot2: Setting Geom_Bar Baseline to 1 Instead of Zero
Add X and Y Axis to All Facet_Wrap
Replace Column Values With Na Based on a Different Column or Row Position With Tidyverse
How to Find the Difference in Value in Every Two Consecutive Rows in R
Append Data Frames Together in a for Loop
How to Keep Columns When Grouping/Summarizing
Subtracting Two Columns to Give a New Column in R
How to Remove the Negative Values from a Data Frame in R
Creating a for Loop to Subset Data on R
Reorder Levels of a Factor Without Changing Order of Values
Warning Message: in '...': Invalid Factor Level, Na Generated
Position Geom_Text on Dodged Barplot
Generate List of All Possible Combinations of Elements of Vector