【问题标题】:geom_rect does not respect x and y limits in for loopgeom_rect 不遵守 for 循环中的 x 和 y 限制
【发布时间】:2019-11-08 20:59:53
【问题描述】:

我试图在for 循环中使用geom_rect,但它不尊重我的限制。如果我在 for 循环的上下文之外调用它,它会这样做。这是一个错误吗?或者我对geom_rect 有什么不明白的地方? outPlot_freeoutPlot1 应该相同(因为 .2 = .2/1),但 outPlot1 中的矩形被截断,有趣的是它们与 outPlot2outPlot3outPlot4 相同。

library('ggplot2')
library('ggrepel')

sum_df <- data.frame(matrix(NA, nrow=10, ncol=3))
colnames(sum_df) <- c("Variable", "Male", "Female")
sum_df$Variable <- c("a", "b", "c", "d", "e", "f", "g", "h", "i", "j")

covar = .7*.1*.1
Sigma = matrix(ncol=2,nrow=2,c(.2^2,covar,covar,.2^2))
temp = eigen(Sigma)
SqrtSigma = temp$vectors%*%diag(sqrt(temp$values))%*%t(temp$vectors)
XYvec = c(0,0) + SqrtSigma%*%rnorm(2)

for(i in 1:10){
  XYvec = c(0,0) + SqrtSigma%*%rnorm(2)
  sum_df$Female[i] = XYvec[1]
  sum_df$Male[i] = XYvec[2]
}

outPlot_free <- ggplot(sum_df, aes(x=Male, y=Female)) + theme_minimal() + 
  geom_rect(aes(xmin=-.2, xmax=.2, ymin=-Inf, ymax=Inf), fill="grey97", color=NA, alpha=.5, size=0) +
  geom_rect(aes(ymin=-.2, ymax=.2, xmin=-Inf, xmax=Inf), fill="grey97", color=NA, alpha=.5, size=0) +
  geom_point() + geom_text_repel(aes(label=Variable)) +
  scale_x_continuous(limits=c(-1, 1), breaks=round(seq(-1, 1, .1), digits=2)) + 
  scale_y_continuous(limits=c(-1, 1), breaks=round(seq(-1, 1, .1), digits=2)) +
  geom_abline(intercept=0, slope=1, linetype="dotdash", alpha=.5) +
  scale_color_manual(values=c("grey60", "black")) + xlab("Female") + ylab("Male") +
  geom_hline(yintercept=.2, linetype="dashed", color="slateblue") + geom_vline(xintercept=.2, linetype="dashed", color="slateblue") +
  geom_hline(yintercept=-.2, linetype="dashed", color="slateblue") + geom_vline(xintercept=-.2, linetype="dashed", color="slateblue") 

for (q in 1:4) {
  covar = .7*.1*.1
  Sigma = matrix(ncol=2,nrow=2,c(.2^2,covar,covar,.2^2))
  temp = eigen(Sigma)
  SqrtSigma = temp$vectors%*%diag(sqrt(temp$values))%*%t(temp$vectors)
  XYvec = c(0,0) + SqrtSigma%*%rnorm(2)

  for(i in 1:10){
    XYvec = c(0,0) + SqrtSigma%*%rnorm(2)
    sum_df$Female[i] = XYvec[1]
    sum_df$Male[i] = XYvec[2]
  }


  outPlot <- ggplot(sum_df, aes(x=Male, y=Female)) + theme_minimal() + 
    geom_rect(aes(xmin=-.2/q, xmax=.2/q, ymin=-Inf, ymax=Inf), fill="grey97", color=NA, alpha=.5, size=0) +
    geom_rect(aes(ymin=-.2/q, ymax=.2/q, xmin=-Inf, xmax=Inf), fill="grey97", color=NA, alpha=.5, size=0) +
    geom_point() + geom_text_repel(aes(label=Variable)) +
    scale_x_continuous(limits=c(-1, 1), breaks=round(seq(-1, 1, .1), digits=2)) + 
    scale_y_continuous(limits=c(-1, 1), breaks=round(seq(-1, 1, .1), digits=2)) +
    geom_abline(intercept=0, slope=1, linetype="dotdash", alpha=.5) +
    scale_color_manual(values=c("grey60", "black")) + xlab("Female") + ylab("Male") +
    geom_hline(yintercept=.2, linetype="dashed", color="slateblue") + geom_vline(xintercept=.2, linetype="dashed", color="slateblue") +
    geom_hline(yintercept=-.2, linetype="dashed", color="slateblue") + geom_vline(xintercept=-.2, linetype="dashed", color="slateblue") 

  assign(paste0("outPlot", q), outPlot)
}

outPlot_free

outPlot1

outPlot2

outPlot3

outPlot4

reprex package (v0.3.0) 于 2019 年 11 月 9 日创建

outPlot_freeoutPlot1 应该是相同的,除了绘制的点,因为它们是独立模拟的。

【问题讨论】:

  • *outPlot_free 和 outPlot1 应该是相同的,除了绘制的点,因为它们是独立模拟的
  • 好吧,如果您提供一个仅关注非工作部分的最小示例,那会更容易。无论如何,您指的是哪些限制?

标签: r pdf ggplot2 limit


【解决方案1】:

您遇到的问题是 R 中的惰性求值。在编写包含循环的代码时,这是一个常见问题,尤其是当您从程序性思维方式处理该语言时。有关更多详细信息,请参见例如这里:http://adv-r.had.co.nz/Functions.html

在以下示例中,第一个是您正在做的事情(实际上),第二个是您应该做的事情。

# doesn't work as expected, as the variable i in the function call
# is evaluated only after the loop is run
x <- list()
for (i in 1:3) {
  x[[i]] <- function() {i}
}
x[[1]]()
#> [1] 3
x[[2]]()
#> [1] 3
x[[3]]()
#> [1] 3

# by writing a function generator, we can bind the variable i
# to the specific function we're generating in each iteration
# of the loop
x <- list()
f_generator <- function(i) {
  force(i)
  function() {i}
}
for (i in 1:3) {
  x[[i]] <- f_generator(i)
}
x[[1]]()
#> [1] 1
x[[2]]()
#> [1] 2
x[[3]]()
#> [1] 3

reprex package (v0.3.0) 于 2019 年 11 月 9 日创建

在您的代码上下文中,编写一个生成绘图的函数,对该函数的所有参数调用force(),然后在for() 循环内调用该函数以创建您需要的特定绘图对象。请参阅以下示例。

library(ggplot2)
library(cowplot)

# this doesn't work, the line in the first plot should be placed
# at y = 1 but is placed at y = 2
plots <- list()
for (i in 1:2) {
  data <- data.frame(x = c(0, 1))
  plots[[i]] <- ggplot(data, aes(x, y = i)) + geom_line() + ylim(0, 3)
}

plot_grid(plotlist = plots, labels = c(1:2))

# this does work
plots <- list()
plot_fun <- function(i) {
  force(i)
  data <- data.frame(x = c(0, 1))
  ggplot(data, aes(x, y = i)) + geom_line() + ylim(0, 3)
}
for (i in 1:2) {
  plots[[i]] <- plot_fun(i)
}

plot_grid(plotlist = plots, labels = c(1:2))

最后,一旦你编写了一个生成绘图的函数,R 中的惯用方法是不编写for 循环,而是使用lapply()map()。事实证明,如果您习惯使用这些函数而不是 for 循环,那么您遇到问题的可能性就会大大降低,因为 R 不是一种过程语言。

# this replaces the for loop
plots <- lapply(1:2, plot_fun)

plot_grid(plotlist = plots, labels = c(1:2))

reprex package (v0.3.0) 于 2019 年 11 月 9 日创建

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 2021-01-08
    • 1970-01-01
    相关资源
    最近更新 更多