2017-07-21 86 views
2

我正在處理來自所有50個州的數據。我試圖用一條線作爲狀態(藍色),另一條作爲全國平均值(灰色)來繪製小型多條折線圖。ggplot2:無法使用geom_ribbon在相交線之間着色區域

這裏是緬因州的一個例子:

enter image description here

這裏是緬因州我的數據幀的樣子:

enter image description here

我想樹蔭所在區域的狀態線落在全國平均紅色以下,當它在綠色之上時。

我用geom_ribbon遮陽面積,並得到一種顏色(規模不同): enter image description here

不過,我在努力尋找一種方法來改變填充時態線越國線。

當我運行這段代碼:

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

https://stackoverflow.com/a/37979793/3330437 – Brian

+0

感謝您的鏈接,@布賴恩。但是該解決方案不起作用。使用該答案中的方法繪製線條時,陰影區域甚至不會出現。我的兩條線都是黑色的。 – AldoTheApache

回答

1

有解決方法,但它看起來像你可能有每個狀態的這些值,用方面來組織它們。在這種情況下,我們儘量將其設置爲「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高度,狀態值較高時在兩個值之間伸展。

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) 

enter image description here

這主要工作,但你可以看到,這是一個有點古怪的交叉點上發生的,因爲他們沒有在今年的x值恰好跨越:

enter image description here

要解決這個問題,我們需要沿着每條線段進行插值,直到這些間隙與眼睛無法區分爲止。我們將爲此使用purrr::map_df。我們首先將split的數據放入一個數據幀列表中,每個狀態一個。然後我們沿着該列表map,創建1)插值年份和狀態值,2)插值年份和國家平均值,以及3)每個狀態的標籤。


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功能默認返回一個名爲xy名單,但我們把它強制轉換爲數據框,並使用state =nat =參數重新標記它。請注意,插入的年份在每行中都是相同的值,所以我們可以在此處拋出其中一列。我們也可以重新命名這些列,但我會保留它。

現在我們可以修改上面的代碼來使用這個新創建的插值數據框。

ggplot(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) 

enter image description here

現在的路口是乾淨多了。此解決方案的解決方案由approx(...)的兩個調用的n =參數控制。

enter image description here