I have the following data set:
tax <- tribble(
~ Country, ~ `1970`, ~ `1979`,
"Sweden", 46.9, 57.4,
"Netherlands", 44.0, 55.8,
"Norway", 43.5, 52.2,
"Britain", 40.7, 39.0,
"France", 39.0, 43.4,
"Germany", 37.5, 42.9,
"Belgium", 35.2, 43.2,
"Canada", 34.9, 35.8,
"Finland", 34.9, 38.2,
"Italy", 30.4, 35.7,
"United States", 30.3, 32.5,
"Greece", 26.8, 30.6,
"Switzerland", 26.5, 33.2,
"Spain", 22.5, 27.1,
"Japan", 20.7, 26.6
)
I am trying to create a slopegraph (x axis 1970, and 1979) y axis the values from the years, and create labels for the countries. However I am running into the problem that some of the values aren't unique so they lay on top of eachother. This isn't the behavior that I want, I want each point to have a unique position on the axis. Im trying to recreate a plot as practice. So far the code I have: (haven't gone much deeper on polishing the plot or adding the labels because I can't seem to figure out how to get the points to not overlap.) I have tried jittering them but it doesn't work as intended.
tax |>
pivot_longer(
cols=c("1970", "1979"),
names_to="Year",
values_to="Tax"
) |>
ggplot() +
geom_line(
aes(x=Year, y=Tax, group=Country)
) +
geom_point(
aes(x=Year, y=Tax, group=Country)
)
I may be overlooking other options, but I think your best bets are either using repel or changing scales - using both might work best.
I don't think there's a perfect solution to your problem, but a lot of publications (NYTimes & such) touch up visualizations in photoshop or other tools to get the type of image you shared...
You can create a label and using the geom_text_repel parameters to get your text to layout the way you like. The size of your plot output will matter, so you'll want to use the export button in the plot panel to set a size of your plot and keep rerunning until you get it formatted as you like. For example, the first image below if from my reprex, but the second is a plot I exported with a width of 800 and a height of 1200.
library(tidyverse)
library(glue)
library(ggrepel)
tax <- tribble(
~ Country, ~ `1970`, ~ `1979`,
"Sweden", 46.9, 57.4,
"Netherlands", 44.0, 55.8,
"Norway", 43.5, 52.2,
"Britain", 40.7, 39.0,
"France", 39.0, 43.4,
"Germany", 37.5, 42.9,
"Belgium", 35.2, 43.2,
"Canada", 34.9, 35.8,
"Finland", 34.9, 38.2,
"Italy", 30.4, 35.7,
"United States", 30.3, 32.5,
"Greece", 26.8, 30.6,
"Switzerland", 26.5, 33.2,
"Spain", 22.5, 27.1,
"Japan", 20.7, 26.6
) %>%
pivot_longer(
cols=c("1970", "1979"),
names_to="Year",
values_to="Tax"
) |>
mutate(text = if_else(Year == "1970", glue("{Country} {Tax}"), glue("{Tax} {Country}")))
tax |> ggplot(aes(x=Year, y=Tax, group=Country)) +
geom_line() +
ggrepel::geom_text_repel(
data = tax |> filter(Year == "1970"),
aes(label = text),
nudge_x = -.2,
force = 2
) +
ggrepel::geom_text_repel(
data = tax |> filter(Year == "1979"),
aes(label = text),
nudge_x = .2,
force = 2
) +
theme_minimal() +
theme(panel.grid = element_blank())
Created on 2024-05-01 with reprex v2.0.2
You can try to use a transformation to scale your y-axis enough to get separation. This approach can be tricky because as your create separation between the close values, you push the bigger values (e.g. Sweden & Netherlands) further away which smashes all your smaller data together. There are several transformation functions you can use in the scales package to try to do better than I did with log2.
library(tidyverse)
library(glue)
library(ggrepel)
tax <- tribble(
~ Country, ~ `1970`, ~ `1979`,
"Sweden", 46.9, 57.4,
"Netherlands", 44.0, 55.8,
"Norway", 43.5, 52.2,
"Britain", 40.7, 39.0,
"France", 39.0, 43.4,
"Germany", 37.5, 42.9,
"Belgium", 35.2, 43.2,
"Canada", 34.9, 35.8,
"Finland", 34.9, 38.2,
"Italy", 30.4, 35.7,
"United States", 30.3, 32.5,
"Greece", 26.8, 30.6,
"Switzerland", 26.5, 33.2,
"Spain", 22.5, 27.1,
"Japan", 20.7, 26.6
) %>%
pivot_longer(
cols=c("1970", "1979"),
names_to="Year",
values_to="Tax"
) |>
mutate(text = if_else(Year == "1970", glue("{Country} {Tax}"), glue("{Tax} {Country}")))
tax |> ggplot(aes(x=Year, y=Tax, group=Country)) +
geom_line() +
geom_text_repel(
data = tax |> filter(Year == "1970"),
aes(label = text),
nudge_x = -.2,
force = 2
) +
geom_text_repel(
data = tax |> filter(Year == "1979"),
aes(label = text),
nudge_x = .2,
force = 2
) +
theme_minimal() +
theme(panel.grid = element_blank())
tax |> ggplot(aes(x=Year, y=Tax, group=Country)) +
geom_line() +
geom_text(
data = tax |> filter(Year == "1970"),
aes(label = text),
nudge_x = -.2
) +
geom_text(
data = tax |> filter(Year == "1979"),
aes(label = text),
nudge_x = .2
) +
scale_y_continuous(trans = scales::log2_trans()) +
theme_minimal() +
theme(panel.grid = element_blank())
Created on 2024-05-01 with reprex v2.0.2