2016-04-14 48 views
4

我已经阅读了大量的职位有关使用循环的ggplot产生大量图形的图形,但找不到任何解释我的问题...与ggplots环路产生具有相同的值,但不同的标题

我有一个数据框,并试图循环使用92列,为每列创建一个新图。我想将每个绘图保存为一个单独的对象。当我运行我的循环(下面的代码)并打印图形时,所有图形都是正确的。但是,当我使用assign()更改print()命令时,图形不正确。标题正在改变,但它们的图形值完全相同(它们都是最终图形的值)。我发现这一点,因为当我使用plot_grid()生成10个图的数字时,图形标题和轴标签都是正确的,但是这些值是相同的!

我的数据集很大,所以我提供了一个小数据集供下面的图解说明。

样品datafame:

library(ggplot) 
library(cowplot) 
df <- as.data.frame(cbind(group=c(rep("A", 4), rep("B", 4)), a=sample(1:100, 8), b=sample(100:200, 8), c=sample(300:400, 8))) #make data frame 
cols <- 2:4 #define columns for plots 
for(i in 1:length(cols)){ 
    df[,cols[i]] <- as.numeric(as.character(df[,cols[i]])) 
} #convert columns to numeric 

图:

for (i in 1:length(cols)){ 
    g <- ggplot(df, aes(x=group, y=df[,cols[i]])) + 
    geom_boxplot() + 
    ggtitle(colnames(df)[cols[i]]) 
    print(g) 
    assign(colnames(df)[cols[i]], g) #generate an object for each plot 
} 

plot_grid(a, b, c) 

我想,当ggplots使情节,它只是呈现从我的终值数据?或者像那样的东西?有没有解决的办法?

我希望这样做,因为有很多图我想做,然后我想混合和匹配数字图。

谢谢!

回答

2

有两种标准的方式来处理这个问题:

1-用长格式data.frame

2 - 使用aes_string引用变量名在宽幅data.frame工作

下面是可能的策略说明。

library(ggplot2) 
library(gridExtra) 

# data from other answer 
df <- data.frame(group=c(rep("A", 4), rep("B", 4)), 
       a=sample(1:100, 8), 
       b=sample(100:200, 8), 
       c=sample(300:400, 8)) 

## first method: long format 
m <- reshape2::melt(df, id = "group") 
p <- ggplot(m, aes(x=group, y=value)) + 
    geom_boxplot() 

pl <- plyr::dlply(m, "variable", function(.d) p %+% .d + ggtitle(unique(.d$variable))) 
grid.arrange(grobs=pl) 

## second method: keep wide format 
one_plot <- function(col = "a") ggplot(df, aes_string(x="group", y=col)) + geom_boxplot() + ggtitle(col) 
pl <- plyr::llply(colnames(df)[-1], one_plot) 
grid.arrange(grobs=pl) 

## third method: more explicit looping 

pl <- vector("list", length = ncol(df)-1) 
for(ii in seq_along(pl)){ 
    .col <- colnames(df)[-1][ii] 
    .p <- ggplot(df, aes_string(x="group", y=.col)) + geom_boxplot() + ggtitle(.col) 
    pl[[ii]] <- .p 
} 

grid.arrange(grobs=pl) 

有时候,包装函数内部ggplot呼叫/ for循环时,一个面临着局部变量的问题(不是这里的情况,如果使用aes_string)。在这种情况下,人们可以define a local environment

请注意,使用像aes(y=df[,i])这样的构造似乎可行,但可能会产生非常错误的结果。 Consider a facetted plot,data.frame将被拆分为每个面板的不同组,并且如果将数值直接传递到aes()而不是变量名称,则此子集可能会惨败,从而对正确的数据进行分组。

3

我清理了您如何生成您的示例数据框。

library(ggplot2) 
library(cowplot) 

df <- data.frame(group=c(rep("A", 4), rep("B", 4)), 
          a=sample(1:100, 8), 
          b=sample(100:200, 8), 
          c=sample(300:400, 8)) #make data frame 

只要使用data.frame()就足够了。这使得你的代码更加清晰,并避免了在'for循环'中将所有后处理转换为数字并去除生成的因素的需求 - 请注意,as.data.frame()和cbind()倾向于默认如果您没有'stringsAsFactors = FALSE',则可以通过使用cbind.data.frame()而不是cbind()来避免数字转换为字符转换。

我也重构了你的'for循环'来产生你的情节。您生成一个名为'cols'的整数列表(cols < - 2:4),然后您重复这些列表以从每列数据生成您的图。这是不必要的,我们可以在for语句条件中创建一个范围 - 'for(i in 2:ncol(df))' - 这仅仅重申2到4(数据框中的列数) - 从2开始需要避免包含元数据的第1列。这是优选的,因为:

i)在审查您的代码中使用的条件是显而易见的,而不通过您的代码

II的其余部分搜索)R具有多个功能/参数类似命名到您的变量“COLS '最好避免混淆。

随着代码的清理,我们现在可以尝试找出错误的原因:

library(ggplot2) 
library(cowplot) 

df <- data.frame(group=c(rep("A", 4), rep("B", 4)), 
          a=sample(1:100, 8), 
          b=sample(100:200, 8), 
          c=sample(300:400, 8)) #make data frame 


for (i in 2:ncol(df)){ 

    g <- ggplot(df, aes(x=group, y=df[,i])) + 
    geom_boxplot() + 
    ggtitle(colnames(df)[i]) 

    print(g) 
    assign(colnames(df)[i], g) #generate an object for each plot 
} 

它不是立即显而易见的,为什么你的代码不能正常工作。伊莫的建议有其优点。将你的图保存到列表中可以防止你的环境变得混乱,但是它不能解决这个问题。原因不直观,需要深入了解assign()函数的评估方式。请参阅提供的答案hereKonrad Rudolph提供。以下应该工作并保留原始代码的风格。正如康拉德在他的回答中所暗示的那样,它可能更像“R”喜欢用乐器。请注意,我们给出了用于循环本地范围,我们现在重新定义本地范围。以前,循环中生成的i的最后一个值用于生成通过assign()函数创建的每个对象。请注意使用< < - 将g分配给全球环境。

for (i in 2:ncol(df)) 
    local({ 
    i <- i 
    g <<- ggplot(df, aes(x=group, y=df[,i])) + 
    geom_boxplot() + 
    ggtitle(colnames(df)[i]) 
    print(i) 
    print(g) 
    assign(colnames(df)[i], g, pos =1) #generate an object for each plot 
    }) 

plot_grid(a, b, c) 

你欠我一杯。

+0

非常感谢您的详细解答Graeme。我必须想一想,当地在做什么,并重新定义'我'。 – Harry

+0

'aes()'应该引用变量名称,而不是数字向量,如'df [,i]'。这样做会导致意想不到的结果,如绘制错误的数据而不注意。更不要说使用'<< - '或者'assign'几乎总是一个清楚的迹象,表明R中的问题会出错。 – baptiste

相关问题