Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Plotting change as bar between the values with ggplot

I would like to plot change between values as a single bar between values as Economist does:

enter image description here

This plot is called dumbbell, so question is likely to be a duplicate if you know what to search for.

Here is a code example that makes a bar plot for two categories. It would be great to be able to plot it per example above.

library(ggplot2)
library(ggthemes)
Animals <- read.table(
  header=TRUE, text='Year        Reason Species
1   2018       Genuine      24
2   2019      Genuine      16
3   2019 Misclassified      85
4   2018 Misclassified      41
5   2018     Taxonomic       2
6   2019     Taxonomic       7
7   2018       Unclear      41
8   2019       Unclear     117')

Animals$Year <- as.character(Animals$Year)

ggplot(Animals, aes(factor(Reason), Species, fill = Year)) + 
  geom_bar(stat="identity", position = "dodge") + 
  scale_fill_brewer(palette = "Set1") + 
  theme_economist() + 
  coord_flip()

Ability to colour decrease as pink (for example) would be a bonus.

enter image description here

like image 282
Bulat Avatar asked Jul 30 '26 15:07

Bulat


1 Answers

Here is a possible solution where I use a second, auxiliary data.frame along with geom_segment() to draw a connecting line between the two timepoints. I've also included some visual customizations like colors, point type, transparency, and arrows. These can be removed or modified as needed.

# Auxiliary data.frame to draw segments.
adat = reshape2::dcast(data=Animals, 
                       formula=Reason ~ Year, 
                       value.var="Species")
adat
#          Reason 2018 2019
# 1       Genuine   24   16
# 2 Misclassified   41   85
# 3     Taxonomic    2    7
# 4       Unclear   41  117

# Colors selected from 
# https://yutannihilation.github.io/allYourFigureAreBelongToUs/ggthemes/economist_pal/
year_colors = c("2018"="#D7D29E", "2019"="#82C0E9")

p1 = ggplot() +
    theme_economist() +
    geom_point(data=Animals, 
               aes(y=Reason, x=Species, fill=Year),
               size=6, shape=21, color="grey30") +
    geom_segment(data=adat, 
                 aes(y=Reason, yend=Reason, x=`2018`, xend=`2019`),
                 size=1.8, color="grey30",
                 lineend="butt", linejoin="mitre",
                 arrow=arrow(length = unit(0.02, "npc"), type="closed")) +
    scale_fill_manual(values=year_colors)

p2 = ggplot() +
     theme_economist() +
     geom_segment(data=adat, 
                  aes(y=Reason, yend=Reason, x=`2018`, xend=`2019`),
                  size=6, color="#82C0E9", alpha=0.6, lineend="butt") +
     geom_point(data=Animals, 
                aes(y=Reason, x=Species, color=Year),
                size=6) +
     xlab("Species") +
     scale_color_manual(values=c("2018"="#C10534", "2019"="#008BBC"))

ggsave("segment_plot_1.png", plot=p1, width=8, height=2.5, dpi=150)
ggsave("segment_plot_2.png", plot=p2, width=8, height=2.5, dpi=150)

# Basic version.
p3 = ggplot() +
     geom_point(data=Animals, aes(y=Reason, x=Species, color=Year)) +
     geom_segment(data=adat, aes(y=Reason, yend=Reason, x=`2018`, xend=`2019`))

ggsave("segment_plot_3.png", plot=p3, width=8, height=2.5, dpi=150)

enter image description here

enter image description here

enter image description here

like image 179
bdemarest Avatar answered Aug 02 '26 07:08

bdemarest



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!