Reputation: 6969
I would like to plot change between values as a single bar between values as Economist does:
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.
Upvotes: 3
Views: 655
Reputation: 6969
I have found geom function in ggalt package that does something like this:
library(ggalt)
library(data.table)
Animals <- data.table(Animals)
Animals.wide <- dcast(Animals, Reason ~ Year, value.var = "Species")
colnames(Animals.wide) <- c("Reason", "species.2018", "species.2019")
p <- ggplot(
Animals.wide,
aes(
y = Reason,
x = species.2018,
xend = species.2019
)
)
# > Animals.wide
# Reason species.2018 species.2019
# 1: Genuine 24 16
# 2: Misclassified 41 85
# 3: Taxonomic 2 7
# 4: Unclear 41 117
p <- p + geom_dumbbell(
size = 10,
color = "#C1D9E4",
colour_x = "#39C1D1",
colour_xend = "#953D4D",
dot_guide = TRUE,
dot_guide_size = 0.25,
position = position_dodgev(height = 0.4),
show.legend = TRUE
)
p <- p + scale_x_continuous(position = "top")
p <- p + theme_economist()
p <- p + xlab("Species")
p <- p + ylab(NA)
p <- p + theme(
legend.position = "top",
axis.text.y = element_text(size = 20),
axis.title.y = element_blank(),
axis.title.x = element_blank(),
axis.line.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.x = element_text(size = 20, margin = margin(-0.4, unit = "cm"))
)
p
It is not as flexible as solution from @bdemarest, but almost does the job.
Upvotes: 2
Reputation: 14667
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)
Upvotes: 2