当输入数据是列表数据帧

时间:2016-10-17 18:31:10

标签: r dynamic ggplot2 colors legend

我想在同一图形中为每个数据框的不同颜色绘制单独数据帧的线条。我可以使用几乎相同的代码和aes(color =“hard-coded-name”)获得一个图例,但我不知道提前的名字。我没有足够的RAM来将数据帧转换为单个数据帧。我写了一个用彩色线条生成图表的样本。如何添加图例?与示例中一样,您不知道列表中有多少数据帧(ldf)或它们的名称是什么。

library('ggplot2')

f30 <- function() {
    ###############################################################
    ##### Create a list with a random number of data frames #######
    ##### The names of the list elements are "random"       #######
    ###############################################################
    f1 <- function(i) {
        b <- sample(1:10, sample(8:10, 1))
        a <- sample(1:100, length(b))
        data.frame(Before = b, After = a)
    }
    ldf <- sapply(1:sample(2:8,1), f1, simplify = FALSE)
    names(ldf) <- LETTERS[sample(1:length(LETTERS), length(ldf))]

    palette <- c(
        "#000000", "#E69F00", "#56B4E9", "#009E73", 
        "#F0E442", "#0072B2", "#D55E00", "#CC79A7"
    )

    ###############################################################
    ##### Above this point we're just creating a sample ldf #######
    ###############################################################

    ePlot <- new.env(parent = emptyenv())
    fColorsButNoLegend <- function(ix) {
        df <- ldf[[ix]]
        n <- names(ldf)[ix]
        if (ix == 1) {
            ePlot$p <- ggplot(df, aes(x = Before, y = After)) + 
                geom_line(colour = palette[ix])
        } else {
            ePlot$p <- ePlot$p + 
                geom_line(
                    colour = palette[ix],
                    aes(x = Before, y = After), 
                    df
                )
        }
    }
    sapply(1:length(ldf), fColorsButNoLegend)

    #Add the title and display the plot
    a <- paste(names(ldf), collapse = ', ')
    ePlot$p <- ePlot$p + 
        ggtitle(paste("Before and After:", a))
    ePlot$p
}

2 个答案:

答案 0 :(得分:1)

暂时搁置一下你是否需要制作一个比RAM中可容纳的数据更多的线图的问题。由于列表元素已命名,您可以使用这些名称生成颜色图例,即使您事先不知道这些名称是什么。

例如,在下面的代码中,我将列表元素的名称添加为数据框中的新source列,然后使用该source列作为颜色美学。然后,在打印绘图之前,我添加了scale_colour_manual语句,以便将颜色设置为您的颜色palette

  ePlot <- new.env(parent = emptyenv())
  fColorsButNoLegend <- function(ix) {
    df <- ldf[[ix]]

    # Add name of list element as a new column
    df$source = names(ldf)[ix]

    if (ix == 1) {
      ePlot$p <- ggplot(df, aes(x = Before, y = After, colour=source)) + 
        geom_line()
    } else {
      ePlot$p <- ePlot$p + 
        geom_line(
          aes(x = Before, y = After, colour=source), 
          df
        )
    }
  }
  sapply(1:length(ldf), fColorsButNoLegend)

  #Add the title and display the plot
  a <- paste(names(ldf), collapse = ', ')
  ePlot$p <- ePlot$p + 
    ggtitle(paste("Before and After:", a)) +
    scale_colour_manual(values=palette)
  ePlot$p

此函数的输出示例:

f30()

enter image description here

答案 1 :(得分:0)

偶然地,我看到另一个图形包如何提供一个替代图例来节省屏幕空间,我认为,它比添加列或复制数据更有效。我想我会在这里提供它,以防其他人发现它有用。它将图例信息嵌入图表本身的空白区域。请参阅fAnnotate函数 - 这是原始的,但足以提供想法的细菌。

enter image description here     库(&#39; GGPLOT2&#39)

f30 <- function() {
  ###############################################################
  ##### Create a list with a random number of data frames #######
  ##### The names of the list elements are "random"       #######
  ###############################################################
  f1 <- function(i) {
    b <- sample(1:10, sample(8:10, 1))
    a <- sample(1:100, length(b))
    data.frame(Before = b, After = a)
  }
  ldf <- sapply(1:sample(2:8,1), f1, simplify = FALSE)
  names(ldf) <- LETTERS[sample(1:length(LETTERS), length(ldf))]

  palette <- c(
    "#000000", "#E69F00", "#56B4E9", "#009E73", 
    "#F0E442", "#0072B2", "#D55E00", "#CC79A7"
  )

  ###############################################################
  ##### Above this point we're just creating a sample ldf #######
  ###############################################################

  ePlot <- new.env(parent = emptyenv())
  ePlot$xMin <- Inf
  ePlot$xMax <- -Inf
  ePlot$yMin <- Inf
  ePlot$yMax <- -Inf
  fColorsButNoLegend <- function(ix) {
    df <- ldf[[ix]]

    #Compute the boundaries of x and y 
    ePlot$xMin <- min(ePlot$xMin, min(df$Before))
    ePlot$xMax <- max(ePlot$xMax, max(df$Before))
    ePlot$yMin <- min(ePlot$yMin, min(df$After))
    ePlot$yMax <- max(ePlot$yMax, max(df$After))

    n <- names(ldf)[ix]
    if (ix == 1) {
      ePlot$p <- ggplot(df, aes(x = Before, y = After)) + 
        geom_line(colour = palette[ix])
    } else {
      ePlot$p <- ePlot$p + 
        geom_line(
          colour = palette[ix],
          aes(x = Before, y = After), 
          df
        )
    }
  }
  sapply(1:length(ldf), fColorsButNoLegend)

  #Divide by length+1 to leave room on either side of the labels
  xGap <- (ePlot$xMax - ePlot$xMin) / (length(ldf) + 1)
  fAnnotate <- function(ix) {
    x <- ePlot$xMin + (ix * xGap)
    lbl <- paste('---', names(ldf)[ix])
    b <- palette[ix]
    ePlot$p <- ePlot$p + 
      annotate("text", x = x, y = -Inf, vjust = -1, label = lbl, colour = b)
  }
  sapply(1:length(ldf), fAnnotate)

  #Add the title and display the plot
  allNames <- paste(names(ldf), collapse = ', ')
  ePlot$p <- ePlot$p + 
    ggtitle(paste("Before and After:", allNames))
  ePlot$p
}