结合时间趋势图和时间线

问题描述

我想创建一个图(最好使用 ggplot2),在其中我将时间线与时间趋势图一起可视化。

举个实际例子,我对每年的失业率进行了汇总。我还有一个数据集,表明与劳动力市场相关的重要立法变化。因此,我想创建一个时间轴,其中失业率显示在相同的 x 轴(时间)之后。

我已经生成了一些玩具数据,见下面的代码

set.seed(2110)
year <- c(1950:2020)
unemployment <- rnorm(length(year),0.05,0.005)
un_emp <- data.frame(cbind(year,unemployment))


year <- c( 1957,1961,1975,1976,1983,1985,1995,1999,2011,2018)
events <- c("Implemented unemployment benefit","Pre-school became free","Five-day workweek were introduced","Labor law reform 1976","Unemployment benefit were cut in half","Apprenticeship Act allows on-the-job training","Changes in discrimination law","Equal Pay for Equal Work was","9 weeks vacation were introduced","Unemployment benefit were removed")

imp_event  <- data.frame(year,events)

我可以轻松绘制多年来的时间趋势:

library(tidyverse)
                      
ggplot(data = un_emp,aes(x = year,y = unemployment)) + 
  geom_line(color = "#FC4E07",size = 0.5) +
  theme_bw()

Time trend.

但是我如何以一种漂亮而有效的方式在情节中包含事件(在 imp_event 中找到)?我该怎么做?

我的目标是让时间线看起来像 here 中的时间线,但将其与上面显示的时间趋势图结合起来。我该怎么做?

enter image description here

我尝试使用 vline,但无法添加事件标签

谢谢!

解决方法

您可以通过覆盖 from bokeh.models import Div,Button,Column,CustomJS from bokeh.plotting import show button = Button(label='Toggle Div Visibility') div = Div(text = 'Bokeh Div',name = "bokeh_div") # code = "if (div.visible == true) { div.visible = false; } else { div.visible = true; }" # button.js_on_click(CustomJS(args = {'div': div},code = code)) code = "var div = Bokeh.documents[0].get_model_by_name('bokeh_div'); if (div.visible == true) { div.visible = false; } else { div.visible = true; }" button.js_on_click(CustomJS(code = code)) show(Column(button,div)) 调用来实现这一点,但这需要 geom_text()x 值与另一个图中的长度相同,因此您不能只提供它是一个新的 df 并覆盖它。

相反,您可以通过在 y 上执行从 left_joinun_empimp_events 来实现您想要的。因为 year 中每年只有一行,所以您将在 df 中留下 imp_events 的大部分缺失值,这是完美的,因为我怀疑您只希望每个事件都显示为标签一次。

例如:

events

这给了你这样的东西:

enter image description here

您可以查看可用选项并尝试使用 joined_data <- un_emp %>% left_join(imp_event,by = "year") ggplot(data = joined_data,aes(x = year,y = unemployment)) + geom_line(color = "#FC4E07",size = 0.5) + geom_text(data = joined_data,y = unemployment,label = (events),size = 3)) + theme_bw() here

,

我使用了 Jon Spring 的解决方案,但将 geom_segment 替换为 geom_vline,结果接近我想要的结果。最终代码如下所示:


joined_data <- un_emp %>% left_join(imp_event,y = unemployment)) + 
  geom_line(color = "red",size = 0.5) +

  theme_classic() +
  labs(y = "Unemployment rate",x = "Years",caption = "Data from XXXX") +
  geom_vline(data = joined_data %>% filter(!is.na(events)),aes(xintercept = year),color = "gray70",linetype = "dashed") +   
  ggrepel::geom_text_repel(data = joined_data,y = unemployment-0.03,label = str_wrap(events,10)),direction = "y",size = 2.5,lineheight = 0.7,point.padding = 0.8)

产生以下情节: enter image description here

我想奖励@Jon Spring 的赏金,但不确定如何奖励评论。

,

我认为这应该可以解决问题:

首先,我使用 hline 创建轴,使用您为数据设置的平均值作为 y 截距。然后我在事件的数据框中添加了一个变量“高度”,它获取轴的值并添加一个从正态分布中提取的值。我用它来绘制向每个点创建线条的线段。最后,我反转年份标签的 y 位置,使其始终位于线段的另一侧。

library(tidyverse)

set.seed(2110)
year <- c(1950:2020)
unemployment <- rnorm(length(year),0.05,0.005)
un_emp <- data.frame(cbind(year,unemployment))

year <- c( 1957,1961,1975,1976,1983,1985,1995,1999,2011,2018)
events <- c("Implemented unemployment benefit","Pre-school became free","Five-day workweek were introduced","Labor law reform 1976","Unemployment benefit were cut in half","Apprenticeship Act allows on-the-job training","Changes in discrimination law","Equal Pay for Equal Work was","9 weeks vacation were introduced","Unemployment benefit were removed")

imp_event  <- data.frame(year,events) %>% 
  mutate(height = mean(unemployment) + rnorm(n(),0.02))

    ggplot(un_emp) +
  
  geom_hline(yintercept = 0.05) +
  
  geom_line(aes(x = year,y = unemployment),color = "red",alpha = 0.3,size = 1) +
  
  geom_segment(data = imp_event,xend = year,y = 0.05,yend = height)) +
  
  geom_text(data = imp_event,aes(label = year,x = year,y = 0.05 + 0.002 * sign(0.05 - height)),angle = 90,size = 3.5,fontface = "bold",check_overlap = T) +
  
  geom_point(data = imp_event,y = height,fill = as.factor(events)),shape = 21,size = 4) +
  
  scale_x_continuous(name = NULL,labels = NULL) +
  
  scale_fill_discrete(name = "Event") +
  
  scale_y_continuous(name = "Unemployment Rate") +
  
  theme_bw() + 
  
  theme(panel.border = element_blank(),axis.line.y  = element_line(),axis.ticks.x = element_blank(),panel.grid = element_blank(),legend.position="bottom")

enter image description here