在ggplot2中添加手动图例?

时间:2014-09-26 02:14:15

标签: r ggplot2

我正在对相同时间序列数据的两个不同估计进行比较图表。如果原始估计值超过最新估计值,我将以绿色填充两个系列之间的区域,否则为红色。

我有那部分工作,但我想为填充颜色添加一个图例。我在代码的底部尝试了scale_fill_manual,但它似乎没有做任何事情?

以下是代码:

library(ggplot2)
library(scales)
library(colorspace)

# Return a polygon that only plots between yLower and yUpper when yLower is
# less than yUpper.
getLowerPolygon = function(x, yLower, yUpper) {
    # Create the table of coordinates
    poly = data.frame(
        x = numeric(),
        y = numeric())

    lastReversed = (yUpper[1] < yLower[1])
    for (r in 1:length(x)) {
        reversed = (yUpper[r] < yLower[r])
        if (reversed != lastReversed) {
            # Between points r-1 and r, the series intersected, so we need to
            # change the polygon from visible to invisible or v.v.  In either
            # case, just add the intersection between those two segments to the
            # polygon.  Algorithm from:
            # https://en.wikipedia.org/wiki/Line-line_intersection
            # First line: x1,y1 - x2,y2
            x1 = x[r-1]
            y1 = yLower[r-1]
            x2 = x[r]
            y2 = yLower[r]
            # Second line: x3,y3 - x4,y4
            x3 = x[r-1]
            y3 = yUpper[r-1]
            x4 = x[r]
            y4 = yUpper[r]
            # Calculate determinants
            xy12 = det(matrix(c(x1, y1, x2, y2), ncol = 2))
            xy34 = det(matrix(c(x3, y3, x4, y4), ncol = 2))
            x12  = det(matrix(c(x1,  1, x2,  1), ncol = 2))
            x34  = det(matrix(c(x3,  1, x4,  1), ncol = 2))
            y12  = det(matrix(c(y1,  1, y2,  1), ncol = 2))
            y34  = det(matrix(c(y3,  1, y4,  1), ncol = 2))
            # Calculate fraction pieces
            xn = det(matrix(c(xy12, x12, xy34, x34), ncol = 2))
            yn = det(matrix(c(xy12, y12, xy34, y34), ncol = 2))
            d  = det(matrix(c(x12 , y12,  x34, y34), ncol = 2))
            # Calculate intersection
            xi = xn / d
            yi = yn / d
            # Add the point
            poly[nrow(poly)+1,] = c(xi, yi)
        }
        lastReversed = reversed
        # http://stackoverflow.com/questions/2563824
        poly[nrow(poly)+1,] = c(x[r], min(yLower[r], yUpper[r]))
    }

    poly = rbind(poly, data.frame(
        x = rev(x),
        y = rev(yUpper)))

    return(poly)
}

getComparisonPlot = function(data, title, lower_name, upper_name,
                         x_label, y_label, legend_title = '') {

    lightGreen = '#b0dd8d'
    lightRed   = '#fdba9a'

    darkGray = RGB(.8, .8, .8)
    midGray  = RGB(.5, .5, .5)

    plot = ggplot(data, aes(x = x))

    plot = plot + geom_polygon(
        aes(x = x, y = y),
        data = data.frame(
            x = c(data$x, rev(data$x)),
            y = c(data$yLower, rev(data$yUpper))
        ),
        fill = lightRed)

    coords = getLowerPolygon(data$x, data$yLower, data$yUpper)

    plot = plot + geom_polygon(
        aes(x = x, y = y),
        data = coords,
        fill = lightGreen)

    plot = plot + geom_line(
        aes(y = yUpper, color = 'upper'),
        size = 0.5)

    plot = plot + geom_line(
        aes(y = yLower, color = 'lower'),
        size = 0.5)

    plot = plot +
        ggtitle(paste(title, '\n', sep='')) +
        xlab(x_label) +
        ylab(y_label) +
        scale_y_continuous(labels = comma)

    # http://stackoverflow.com/a/10355844/106302
    plot = plot + scale_color_manual(
        name   = legend_title,
        breaks = c('upper' , 'lower'),
        values = c('gray20', 'gray50'),
        labels = c(upper_name, lower_name))

    plot = plot + scale_fill_manual(
        name   = 'Margin',
        breaks = c('upper', 'lower'),
        values = c(lightGreen, lightRed),
        labels = c('Over', 'Under'))

    return(plot)
}

print(getComparisonPlot(
    data = data.frame(
        x = 1:20,
        yLower = 1:20 %% 5 + 2,
        yUpper = 1:20 %% 7
    ),
    title = 'Comparison Chart',
    lower_name = 'Latest',
    upper_name = 'Original',
    x_label = 'X axis',
    y_label = 'Y axis',
    legend_title = 'Thing'
))

这是图表的图像,我认为这是一种很酷的技术:

Comparison Chart

我也对改进我的ggplot代码的任何其他建议持开放态度。

1 个答案:

答案 0 :(得分:7)

GGplot需要您将多边形fill美学映射到某个变量。或者,在这种情况下,只需要“标记”多边形的类型(即“上”和“下”)。您可以通过传递一个字符串来执行此操作,该字符串具有geom_polygon()的填充美学的相应标签。你正在做的是传递每个多边形的给定颜色,而不是映射到ggplot将理解的任何东西。它是一种“硬编码颜色”= P。

嗯,以下是getComparisonPlot内的更改:

plot = plot + geom_polygon(
    aes(x = x, y = y, fill = "upper"),
    data = coords)

plot = plot + geom_polygon(
    aes(x = x, y = y, fill = "lower"),
    data = data.frame(
      x = c(data$x, rev(data$x)),
      y = c(data$yLower, rev(data$yUpper))
    ))

还有一件事。请注意,传递给fill美学的字符串与传递给scale_fill_manual的中断重合。有必要使图例映射正确。

plot = plot + scale_fill_manual(
    name   = 'Margin',
    breaks = c('upper', 'lower'), # <<< corresponds to fill aesthetic labels
    values = c(lightGreen, lightRed),
    labels = c('Over', 'Under'))

结果:

enter image description here

希望它有所帮助。