Has anyone done something similar to this using ggplot2?
Here is one way to start the process.
library(ggplot2)
DF <- data.frame(Party = rep(c("Dem", "Rep"), each = 100),
Value = c(rnorm(100, 45, 10), rnorm(100, 63, 12)),
YMin = rep(c(0,1), each = 100),
YMax = rep(c(0.5,1.5), each = 100))
ggplot(DF, aes(x = Value, color = Party, ymin = YMin, ymax = YMax)) + geom_linerange()
Created on 2020-07-08 by the reprex package (v0.2.1)
2 Likes
going further:
Some thing might need some post-processing, not sure if you can move the x axis labels between the two.
ggplot(DF, aes(x = Value, color = Party, ymin = YMin, ymax = YMax)) +
geom_linerange(alpha = 0.5) +
scale_x_continuous(labels = function(x) paste0(x, "%"),
breaks = seq(0,100,20),
limits = c(0,100)) +
scale_colour_manual(values = c("red3", "royalblue3")) +
theme_minimal(base_size = 14) +
theme(legend.position = "none",
axis.text.x = element_text(),
aspect.ratio = 0.2,
plot.title = element_text(hjust = 0.5),
# somehow theme_void isn't working, so switch off everything we don't need
panel.grid = element_blank(),
axis.text.y = element_blank(),
axis.title.x = element_blank()
) +
labs(title = "Republican landslide counties are \ngenerally whiter than Democratic ones")
2 Likes
You can do that manually via geom_text()
for example:
library(tidyverse)
DF <- data.frame(Party = rep(c("Dem", "Rep"), each = 100),
Value = c(rnorm(100, 45, 10), rnorm(100, 63, 12)),
YMin = rep(c(0,1), each = 100),
YMax = rep(c(0.5,1.5), each = 100))
ggplot(DF, aes(x = Value, color = Party, ymin = YMin, ymax = YMax)) +
geom_linerange(alpha = 0.5) +
geom_text(data = tibble(x = seq(0, 100, by = 20), y = .75,
label = glue::glue("{seq(0, 100, by = 20)}%")),
aes(x = x, y = y, label = label),
inherit.aes = F,
color = "grey40",
size = 3.5) +
scale_colour_manual(values = c("red3", "royalblue3")) +
theme_minimal(base_size = 14) +
theme(legend.position = "none",
aspect.ratio = 0.2,
plot.title = element_text(hjust = 0.5),
# somehow theme_void isn't working, so switch off everything we don't need
panel.grid = element_blank(),
axis.text = element_blank(),
axis.title = element_blank()
) +
labs(title = "Republican landslide counties are \ngenerally whiter than Democratic ones")
Created on 2020-07-09 by the reprex package (v0.3.0)
And going one step further, adding the averages:
library(tidyverse)
DF <- data.frame(Party = rep(c("Dem", "Rep"), each = 100),
Value = c(rnorm(100, 45, 10), rnorm(100, 63, 12)),
YMin = rep(c(0,1), each = 100),
YMax = rep(c(0.5,1.5), each = 100))
DF_avg <- DF %>%
mutate(avg = mean(Value)) %>%
group_by(Party, avg, YMin, YMax) %>%
summarize(avg_party = mean(Value))
#> `summarise()` regrouping output by 'Party', 'avg', 'YMin' (override with `.groups` argument)
ggplot(DF, aes(x = Value, color = Party, ymin = YMin, ymax = YMax)) +
geom_linerange(alpha = 0.5) +
geom_linerange(data = DF_avg,
aes(x = avg_party, color = Party, ymin = YMin - .1, ymax = YMax + .1),
size = 2) +
geom_vline(data = DF_avg,
aes(xintercept = DF_avg$avg), size = 1) +
geom_text(data = tibble(x = seq(0, 100, by = 20), y = .75, label = glue::glue("{seq(0, 100, by = 20)}%")),
aes(x = x, y = y, label = label),
inherit.aes = F,
color = "grey40",
size = 3.5) +
scale_colour_manual(values = c("red3", "royalblue3")) +
theme_minimal(base_size = 14) +
theme(legend.position = "none",
aspect.ratio = 0.2,
plot.title = element_text(hjust = 0.5),
# somehow theme_void isn't working, so switch off everything we don't need
panel.grid = element_blank(),
axis.text = element_blank(),
axis.title = element_blank()
) +
labs(title = "Republican landslide counties are \ngenerally whiter than Democratic ones")
Created on 2020-07-09 by the reprex package (v0.3.0)
6 Likes
A note on the original visualization: I would prefer to add the unit to the axis, either to the 0% or 100% label. It takes a while otherwise to figure out what the percentages represent IMO.
This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.