我正在对相同时间序列数据的两个不同估计进行比较图表。如果原始估计值超过最新估计值,我将以绿色填充两个系列之间的区域,否则为红色。
我有那部分工作,但我想为填充颜色添加一个图例。我在代码的底部尝试了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'
))
这是图表的图像,我认为这是一种很酷的技术:
我也对改进我的ggplot代码的任何其他建议持开放态度。
答案 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'))
结果:
希望它有所帮助。