【问题标题】:Calculate the optimal grid layout dimensions for a given amount of plots in R [closed]计算R中给定数量的图的最佳网格布局尺寸[关闭]
【发布时间】:2015-08-14 19:20:54
【问题描述】:

我在 ggplot 中有 12 个图,我用 grid.arrange 来排列它们。我手动将网格中的行数设置为 4,将列数设置为 3。由于 3 x 4 = 12,这就像一个魅力。

但是如果我有任意数量的地块怎么办?说 13... 我如何以编程方式找到要使用的行数和列数,以使整个绘图成为最“方形”的形状?

我想在 R 中这样做。

更新 数据链接:http://github.com/ngfrey/DataGenii/blob/master/exampleMedicalData.csv

这是我今天早上正在编写的代码。希望它将提供一个更具说明性的示例。请注意我如何在函数的return(list(plots=plots, numrow=4, numcol=3)) 部分设置行数和列数:

makePlots<- function(fdf){
idx<- which(sapply(fdf, is.numeric))
idx<- data.frame(idx)
names(idx)<- "idx"
idx$names<- rownames(idx)
plots<- list()

for(i in 2:length(idx$idx)) {
  varname<- idx$names[i]
  mydata<- fdf[, idx$names[i]]
  mydata<- data.frame(mydata)
  names(mydata)<- varname
  g<- ggplot(data=mydata, aes_string(x=varname) )
  g<- g + geom_histogram(aes(y=..density..), color="black", fill='skyblue')+ geom_density() + xlab(paste(varname))
  print(g)


  plots<- c(plots, list(g))
}

return(list(plots=plots, numrow=4, numcol=3 ))
}
res<- makePlots(fdf)
do.call(grid.arrange, c(res$plots, nrow=res$numrow, ncol=res$numcol))

【问题讨论】:

  • 情节已生成,您事先不知道它们会有多少?
  • 您必须更具体地表达方形的意思,否则ceiling(sqrt(13))?
  • 我每天都会收到多个数据集,每个数据集都有未知数量的数值变量。我想为相应数据集中的每个数值变量创建一个密度图网格。我稍后会添加一个示例。

标签: r rows dimensions


【解决方案1】:

?n2mfrow 为您找到默认布局;实际上,如果缺少nrowncol,它已经被grid.arrange 使用了

grid.arrange(grobs = replicate(7, rectGrob(), simplify=FALSE))

【讨论】:

    【解决方案2】:

    在实践中,可以合理显示的地块数量有限,而美观的布置也很少,因此您可以只制作表格。

    但是,我们可以做的是为较大尺寸与较小尺寸的比率指定一个公差。然后我们找到最接近我们目标的两个数字。如果这些在容忍范围内,我们就完成了。否则,我们会给我们的目标增加浪费。这终止于找到合适的对或下一个最大的正方形中的较早者。 (公差应 > 1)。

    考虑给定n的最接近的两个数字中的最小者

    fact<-function(n) {
      k<-floor(sqrt(n));
      for(i in k:1) {if (n%%i == 0) return(i)}
    }
    

    在容差范围内搜索近正方形

    nearsq<-function(n,tol=5/3+0.001) {
      m<-ceiling(sqrt(n))^2;
      for(i in n:m) {
        a<-fact(i);
        b<-i/a;
        if(b/a < tol) return(c(a,b))
      }
    }
    

    例子

    #probably too many plots
    nearsq(83)
    #> [1]  8 11
    
    #a more reasonable range of plots, tabulated
    cbind(12:36,t(Vectorize(nearsq)(12:36)))
    
    [,1] [,2] [,3] [1,] 12 3 4 [2,] 13 3 5 [3,] 14 3 5 [4,] 15 3 5 [5,] 16 4 4 [6,] 17 4 5 [7,] 18 4 5 [8,] 19 4 5 [9,] 20 4 5 [10,] 21 4 6 [11,] 22 4 6 [12,] 23 4 6 [13,] 24 4 6 [14,] 25 5 5 [15,] 26 5 6 [16,] 27 5 6 [17,] 28 5 6 [18,] 29 5 6 [19,] 30 5 6 [20,] 31 5 7 [21,] 32 5 7 [22,] 33 5 7 [23,] 34 5 7 [24,] 35 5 7 [25,] 36 6 6

    【讨论】:

    • 谢谢!我还找到了另一种方法来解决这个问题。我也会发布我自己的答案!
    【解决方案3】:

    这是我让这个坏男孩工作的方法: (我仍然可以收紧轴标签,并且可能会压缩 makePlots() 函数中的前 2 个 if 语句,以便它运行得更快,但我会在稍后的日期/帖子中解决这个问题)

    library(gmp)
    library(ggplot2)
    library(gridExtra)
    
    ############
    factors <- function(n)
    {
       if(length(n) > 1) 
       {
          lapply(as.list(n), factors)
       } else
       {
          one.to.n <- seq_len(n)
          one.to.n[(n %% one.to.n) == 0]
       }
    }
    
    
    ###########
    makePlots<- function(fdf){
    idx<- which(sapply(fdf, is.numeric))
    idx<- data.frame(idx)
    names(idx)<- "idx"
    idx$names<- rownames(idx)
    plots<- list()
    
    for(i in 2:length(idx$idx)) {
      varname<- idx$names[i]
      mydata<- fdf[, idx$names[i]]
      mydata<- data.frame(mydata)
      names(mydata)<- varname
      g<- ggplot(data=mydata, aes_string(x=varname) )
      g<- g + geom_histogram(aes(y=..density..), color="black", fill='skyblue')+ geom_density() + xlab(paste(varname))
      print(g)
    
    
      plots<- c(plots, list(g))
    }
    
    numplots<- 0
    #Note: The reason I put in length(idx$idx)-1 is because the first column is the row indicies, which are usually numeric ;)
    #isprime returns 0 for non-prime numbers, 2 for prime numbers
    if(length(idx$idx) == 2){
      numplots<- length(idx$idx)
      ncolx<- 1
      nrowx<- 2
    } else if(length(idx$idx)==3){
      numplots<- length(idx$idx)
      ncolx<- 1
      nrowx<- 3
    } else if(isprime((length(idx$idx)-1)) !=0){ 
      numplots<- length(idx$idx)
      facts<- factors(numplots)
      ncolx<- facts[length(facts)/2]
      nrowx<- facts[(length(facts)/2) + 1]
    
    } else{numplots<- (length(idx$idx)-1)
      facts<- factors(numplots)
      ncolx<- facts[length(facts)/2]
      nrowx<- facts[(length(facts)/2) + 1]}
    
    if(abs(nrowx-ncolx)>2){
      ncolx<- ncolx+1
      nrowx<- ceiling(numplots/ncolx)
    }
    
    
    return(list(plots=plots, numrow=nrowx, numcol=ncolx ))
    }
    res<- makePlots(fdf)
    do.call(grid.arrange, c(res$plots, nrow=res$numrow, ncol=res$numcol))
    

    【讨论】:

      猜你喜欢
      • 2016-08-08
      • 2012-03-19
      • 2012-08-08
      • 1970-01-01
      • 1970-01-01
      • 2020-05-27
      • 2018-12-22
      • 1970-01-01
      • 2013-01-17
      相关资源
      最近更新 更多