我处理来自所有50个州的数据。我试图绘制小的多线图,其中一条线是状态(蓝色),另一条线是全国平均值(灰色)。
以下是缅因州的一个例子:
以下是我的缅因州数据框架:
我试图遮蔽状态线低于全国平均红色的区域以及高于绿色的区域。
我已使用geom_ribbon
遮挡区域并获得一种颜色(比例不同):
然而,当状态线越过国界线时,我正在努力寻找改变填充的方法。
当我运行此代码时:
ggplot(states, aes(x = year, group=1)) +
geom_line(aes(y = ttc_avg),colour='#006f91') +
geom_line(aes(y = nat_avg), colour='#666666') +
geom_ribbon(aes(x=year, ymin = nat_avg, ymax = ttc_avg, fill=ttc_avg > nat_avg)) +
scale_fill_manual(values=c("green", "red"), name="fill") +
facet_wrap(~state)
我收到Aesthetics can not vary with a ribbon.
解决这个问题的最佳方法是什么?我应该使用geom_ribbon
还是其他ggplot2函数?
答案 0 :(得分:3)
有一些解决方法,但看起来你可能会为每个州提供这些值,并使用facet来组织它们。在这种情况下,让我们尝试将其作为" tidy"尽可能。在这个构造的假数据中,为了简单起见,我改变了你的变量名,但概念是一样的。
library(dplyr)
library(purrr)
library(ggplot2)
temp.grp <- expand.grid(state = sample(state.abb, 8), year = 2008:2015) %>%
# sample 8 states and make a dataframe for the 8 years
group_by(state) %>%
mutate(sval = cumsum(rnorm(8, sd = 2))+11) %>%
# for each state, generate some fake data
ungroup %>% group_by(year) %>%
mutate(nval = mean(sval))
# create a "national average" for these 8 states
head(temp.grp)
Source: local data frame [6 x 4]
Groups: year [1]
state year sval nval
<fctr> <int> <dbl> <dbl>
1 WV 2008 15.657631 10.97738
2 RI 2008 10.478560 10.97738
3 WI 2008 14.214157 10.97738
4 MT 2008 12.517970 10.97738
5 MA 2008 9.376710 10.97738
6 WY 2008 9.578877 10.97738
这绘制了两条丝带,一条在全国平均线之间,以较小者为准,全国平均值或州值。这意味着当全国平均值较低时,它基本上是一个高度为0的带状物。当全国平均值较高时,带状物在全国平均值和较低的州值之间。
另一个色带与此相反,当状态值较小时为0高度,当状态值较高时,在两个值之间拉伸。
ggplot(temp.grp, aes(year, nval)) + facet_wrap(~state) +
geom_ribbon(aes(ymin = nval, ymax = pmin(sval, nval), fill = "State lower")) +
geom_ribbon(aes(ymin = sval, ymax = pmin(sval, nval), fill = "State higher")) +
geom_line(aes(linetype = "Nat'l Avg")) +
geom_line(aes(year, sval, linetype = "State")) +
scale_fill_brewer(palette = "Set1", direction = -1)
这大部分都有效,但你可以看到交叉点发生时有点奇怪,因为它们并没有完全交叉在x年值:
为了解决这个问题,我们需要沿着每个线段进行插值,直到这些间隙变得难以区分。我们将purrr::map_df
用于此目的。我们首先将split
数据放入数据帧列表中,每个状态一个。然后我们沿着该列表map
创建一个数据帧:1)插值年份和状态值,2)插值年份和全国平均值,以及3)每个州的标签。
temp.grp.interp <- temp.grp %>%
split(.$state) %>%
map_df(~data.frame(state = approx(.x$year, .x$sval, n = 80),
nat = approx(.x$year, .x$nval, n = 80),
state = .x$state[1]))
head(temp.grp.interp)
state.x state.y nat.x nat.y state
1 2008.000 15.65763 2008.000 10.97738 WV
2 2008.089 15.90416 2008.089 11.03219 WV
3 2008.177 16.15069 2008.177 11.08700 WV
4 2008.266 16.39722 2008.266 11.14182 WV
5 2008.354 16.64375 2008.354 11.19663 WV
6 2008.443 16.89028 2008.443 11.25144 WV
approx
函数默认返回名为x
和y
的列表,但我们将其强制转换为数据框,并使用state =
和{{1}重新标记它参数。请注意,插值年份在每一行中都是相同的值,因此我们可以在此时丢弃其中一列。我们也可以重命名列,但我会不管它。
现在我们可以修改上面的代码来处理这个新创建的插值数据帧。
nat =
现在十字路口更干净了。此解决方案的解析由ggplot(temp.grp.interp, aes(nat.x, nat.y)) + facet_wrap(~state) +
geom_ribbon(aes(ymin = nat.y, ymax = pmin(state.y, nat.y), fill = "State lower")) +
geom_ribbon(aes(ymin = state.y, ymax = pmin(state.y, nat.y), fill = "State higher")) +
geom_line(aes(linetype = "Nat'l Avg")) +
geom_line(aes(nat.x, state.y, linetype = "State")) +
scale_fill_brewer(palette = "Set1", direction = -1)
的两次调用的n =
个参数控制。