Jason Heppler Jason Heppler - 3 years ago 151
R Question

Using geom_segment to create a timeline visualization

I am trying to create a chart like this one produced in the NYTimes using ggplot:

Timeline visualization

I think I'm getting close, but I'm not quite sure how to separate out some of my data so I get the right view. My data is political office holders that appear something like this:

name,year_elected,year_left,years_in_office,type,party
Person 1,1969,1969,1,Candidate,Unknown
Person 2,1969,1971,2,Candidate,Unknown
Person 3,1969,1973,4,Candidate,Unknown
Person 4,1969,1973,4,Candidate,Unknown
Person 5,1971,1974,3,Candidate,Unknown
Person 1,1971,1976,5,Candidate,Unknown
Person 2,1971,1980,9,Candidate,Unknown
Person 6,1973,1978,5,Candidate,Unknown
Person 7,1973,1980,7,Candidate,Unknown
Person 8,1975,1980,5,Candidate,Unknown
Person 9,1977,1978,1,Candidate,Unknown


And I've used the below code to get very close to this view, but I think an issue I'm running into is either drawing segments incorrectly (e.g., I don't seem to have a single segment for each candidate), or segments are overlapping/stacking. The key issue I'm running into is my list of office holders is around 60, but my chart is only drawing around 28 lines.

library(googlesheets)
library(tidyverse)

# I'm reading from a Google Spreadsheet
data <- gs_title("Council Members")
data_sj <- gs_read(ss = data, ws = "Sheet1")

ggplot(data, aes(year_elected, years_in_office)) +
geom_segment(aes(x = year_elected, y = 0,
xend = year_left, yend = years_in_office)) +
theme_minimal()


The above code gives me:

Timeline chart

Thanks ahead of time for any pointers!

Answer Source

If your data frame is called d, then:

  • Transform it to data.table
  • Add jitter to year_electer
  • Add equivalent jitter to year_left
  • Add group (as an example) to color your samples

Use ggrepel to add text if there are many points.

Code:

library(data.table)
library(ggplot2)
library(ggrepel)

d[, year_elected2 := jitter(year_elected)]
d[, year_left2 := year_left + year_elected2 - year_elected + 0.01]
d[, group := TRUE]
d[factor(years_in_office %/% 9) == 1, group := FALSE]

ggplot(d, aes(year_elected2, years_in_office)) +
    geom_segment(aes(x = year_elected2, xend = year_left2,
                     y = 0, yend = years_in_office, linetype = group),
                 alpha = 0.8, size = 1, color = "grey") +
    geom_point(aes(year_left2), color = "black", size = 3.3) +
    geom_point(aes(year_left2, color = group), size = 2.3) +
    geom_text_repel(aes(year_left2, label = name), ) +
    scale_colour_brewer(guide = FALSE, palette = "Dark2") +
    scale_linetype_manual(guide = FALSE, values = c(2, 1)) +
    labs(x = "Year elected",
         y = "Years on office") +
    theme_minimal(base_size = 10)

Result:

enter image description here

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download