GGPlot2 Preset - Creating a function with certain ggplot2 aesthetics options [duplicate] - r

This question already has answers here:
Can ggplot theme formatting be saved as an object?
(2 answers)
Closed 1 year ago.
I'm creating quite a few plots at the moment. Since they're all geared towards the same presentation, they have a lot in common in terms of the options I chose to give them their appearance.
df1 <- data.frame(name = c("name1","name2","name3","name4"),
variable = c("var1","var1","var2","var2"),
value = c(15,16,17,18))
df1 %>%
ggplot(aes(x = name, y = value, fill = variable)) +
geom_bar(stat = "identity", position = position_stack()) +
labs(title = "Plot Title",
subtitle = "month 1",
x="",
y="Count") +
scale_fill_viridis_d(name = "", option = "inferno", begin = 0.3, end = 0.7, direction = -1) +
scale_shape_tableau() +
theme_economist() +
theme(plot.background = element_rect(fill = "white"),
plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5),
axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1),
plot.margin = unit(c(1,1,1,1), "cm"))
With the mindset of reducing the number of lines of code, is there a way to create a function with some of those options, such as "theme", "theme_economist", "scale_shape", "scale_fill"? I could then just specify the aesthetics and the labs for each plot, and the rest would just amount to a "+ preset function", to add the themes, colors and shapes.

You can store things to be added to a plot in a list. You can then re-use this list by adding it to a plot.
library(ggplot2)
library(ggthemes)
library(magrittr)
common_options <- list(
scale_fill_viridis_d(name = "", option = "inferno", begin = 0.3, end = 0.7, direction = -1),
scale_shape_tableau(),
theme_economist(),
theme(plot.background = element_rect(fill = "white"),
plot.title = element_text(hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5),
axis.text.x = element_text(angle = 45, vjust = 1, hjust = 1),
plot.margin = unit(c(1,1,1,1), "cm"))
)
df1 <- data.frame(name = c("name1","name2","name3","name4"),
variable = c("var1","var1","var2","var2"),
value = c(15,16,17,18))
df1 %>%
ggplot(aes(x = name, y = value, fill = variable)) +
geom_bar(stat = "identity", position = position_stack()) +
labs(title = "Plot Title",
subtitle = "month 1",
x="",
y="Count") +
common_options
Created on 2021-07-20 by the reprex package (v1.0.0)

Related

R: ggplot2 geom_text by condition (for selected)

I need to copy this bar chart
The problem is that I don't know how to make red and blue labels on the bars and save grey for others. According to the task red labels should highlight whether the character is included in Golden Trio (Harry, Hermione Granger, Ron Weasley). So their bars should contain this red label and others characters should have grey labels.
My code is here:
ggplot(data = actions, aes(x = names_ordered, y = tot)) + geom_bar(stat = "identity",color="grey85", fill="grey90") +
labs(title = "Character aggression \nHarry Potter Universe", caption = "pmsar2020_hw1_shivarova") + theme_classic() +
geom_text(aes(label = tot), size = 3, vjust = 2, colour = "grey30") + theme(plot.title = element_text(hjust = 0.5),
plot.caption.position = "plot",
plot.caption = element_text(hjust = 1,
face = "italic",
color = 'grey60'),
axis.title.x=element_blank(),
axis.title.y =element_blank())
One option would be to add a column to your dataset with the desired color for each category. For the assignment you could e.g. use dplyr::case_when. Afterwards you could map this new column on the color aes and use scale_color_identity:
Using some fake data to mimic your real dataset:
actions <- data.frame(
names_ordered = LETTERS[1:8],
tot = 8:1
)
library(ggplot2)
library(dplyr)
actions$color <- dplyr::case_when(
actions$names_ordered %in% c("A", "C", "D") ~ "darkred",
actions$names_ordered %in% c("E") ~ "blue",
TRUE ~ "grey30"
)
ggplot(data = actions, aes(x = names_ordered, y = tot)) +
geom_bar(stat = "identity", color = "grey85", fill = "grey90") +
labs(title = "Character aggression \nHarry Potter Universe", caption = "pmsar2020_hw1_shivarova") +
theme_classic() +
geom_text(aes(label = tot, color = color), size = 3, vjust = 2) +
scale_color_identity() +
theme(
plot.title = element_text(hjust = 0.5),
plot.caption.position = "plot",
plot.caption = element_text(
hjust = 1,
face = "italic",
color = "grey60"
),
axis.title.x = element_blank(),
axis.title.y = element_blank()
)

duplicating and edit a discrete axis in ggplot2 - 2021

There are a couple of other posts on the same topic, but the solutions proposed do not fit my case.
Given a data frame like this
ddff <- structure(
list(
SampleID = structure(
20:16,
.Label = c(
"S39",
"S30",
"S35",
"S22",
"S23",
"S26",
"S29",
"S24",
"S27",
"S32",
"S37",
"S36",
"S38",
"S34",
"S33",
"S40",
"S25",
"S28",
"S31",
"S21"
),
class = "factor"
),
Counts = c(12177, 14367, 15118, 15312,
16622),
sampleName = structure(
20:16,
.Label = c(
"2Dr",
"2Es",
"1Er",
"1Bs",
"1Cs",
"2As",
"2Ds",
"1Ds",
"2Bs",
"1Br",
"2Br",
"2Ar",
"2Cr",
"1Dr",
"1Cr",
"2Er",
"1Es",
"2Cs",
"1Ar",
"1As"
),
class = "factor"
),
compartment = c("soil", "root", "soil",
"soil", "root")
),
row.names = c(NA, 5L),
class = "data.frame"
)
and the following code
library(tidyverse)
ddff %>%
ggplot(aes(x = Counts, y = SampleID)) +
geom_point(aes(col = compartment), size = 4, alpha = 0.75) +
geom_text(
aes(label = paste0(" ", Counts)),
size = 3,
hjust = 0,
nudge_x = -0.1,
check_overlap = TRUE,
color = "blue"
) +
xlim(NA, 33000) +
theme_light() +
theme(plot.title = element_text(hjust = 0.5), aspect.ratio = 1) +
theme(# remove the vertical grid lines
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank()) +
labs(title = "Library Size Overview",
x = "Read Counts",
color = "Compartment") +
theme(
legend.position = c(.95, .95),
legend.justification = c("right", "top"),
legend.box.just = "right",
legend.box.background = element_rect(color = "black", size = 1)
)
I get this plot
Rplot
I'm interested in adding second labels on the right Y axis, according to the content of the ddff column 'sampleName'. Of course the solution seems to be the usage of scale_y_discrete along with dup_axis, but I'm not able to figure out how...any idea based on recent ggplot evolutions?
Discrete scales in ggplot2 don't support secondary scales (see related issue). The ggh4x package has a manual axis that can work around this limitation. (Disclaimer: I'm the author of ggh4x).
For you example, you could use it like this:
library(ggplot2)
# ddff <- structure(...) # omitted for brevity
ggplot(ddff, aes(x = Counts, y = SampleID)) +
geom_point(aes(col = compartment), size = 4, alpha = 0.75) +
geom_text(
aes(label = paste0(" ", Counts)),
size = 3,
hjust = 0,
nudge_x = -0.1,
check_overlap = TRUE,
color = "blue"
) +
xlim(NA, 33000) +
guides(y.sec = ggh4x::guide_axis_manual(
breaks = ddff$SampleID, labels = ddff$sampleName
))
However, you may need to deduplicate data in the axis if there are multiple observations per y-axis category (which isn't the case in the example).
This is a dupe of the ..., and adapting its solution to this is merely adding the scale_y_continuous and setting the y axis label. Unlike teunbrand's excellent answer (I'm a fan of teunbrand's packages/work), this is base ggplot2.
(This also alters the order, since we're now "counting" along the samples.)
ddff %>%
ggplot(aes(x = Counts, y = seq_along(SampleID))) +
geom_point(aes(col = compartment), size = 4, alpha = 0.75) +
geom_text(
aes(label = paste0(" ", Counts)),
size = 3,
hjust = 0,
nudge_x = -0.1,
check_overlap = TRUE,
color = "blue"
) +
xlim(NA, 33000) +
theme_light() +
theme(plot.title = element_text(hjust = 0.5), aspect.ratio = 1) +
theme(# remove the vertical grid lines
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank()) +
labs(title = "Library Size Overview",
x = "Read Counts",
y = "SampleID", # <-- new
color = "Compartment") +
theme(
legend.position = c(.95, .95),
legend.justification = c("right", "top"),
legend.box.just = "right",
legend.box.background = element_rect(color = "black", size = 1)
) +
# new
scale_y_continuous(
breaks = seq_len(nrow(ddff)), labels = ddff$SampleID,
sec.axis = sec_axis(~., breaks = seq_len(nrow(ddff)),
labels = ddff$sampleName)
)

how to remove a break in geom_line

Using the code below, I have created my plot of interest. The only issue is the break between the brown line the rest of the four lines (Year=205). How can I solve this by joining the brown line to the other four lines?
Thanks,
Nader
UN_2010_plot <- ggplot()+
geom_line(aes(x =Year, y =Population , group=Variant, colour = Variant), data = UN_2010)+
ggrepel::geom_text_repel(aes(x =Year+10, y = Population, colour = Variant, label = Variant, fontface = 'bold'), data = UN_2010 %>%
filter(Year == max(Year)),
segment.color = 'transparent',
direction = "y",
size = 3,
box.padding = 0,
force = 0
) +
theme_bw() +
theme(panel.border = element_blank(), panel.grid.major = element_blank(),
panel.grid.minor = element_blank(), axis.line = element_line(colour = "black"),
strip.background = element_rect(
color="white", fill="white", size=1.5, linetype="solid"
))+
theme(legend.position = "none") +
scale_x_continuous(breaks=seq(1950,2100,10))+
scale_y_continuous(breaks=seq(10000,150000,10000))+
coord_cartesian(ylim = c(10000, 150000))+
labs(
x = NULL,
y = "Population (thousands)",
caption = (NULL),
face = "bold"
) +
ggtitle("The 2010 Revision") +
theme(plot.title = element_text(hjust = 0.5))+
theme(axis.text.x = element_text(angle = -45, vjust = 0.5, hjust=0))
UN_2010_plot
As stefan already mentioned. Here is the psuedo code that fixed your data which would connect the ending lines with starting line.
additional_data <- tibble(Year = rep(2010, 4),
Population = rep(UN_2010$Population[Year == "2010"], 4),
Variant <- c("Low", "Medium", "Constant", "High"))
UN_2010_new <- bind_rows(UN_2010, additional_data) %>% arrange(Year, Variant)

How to add a free text entry as a legend to ggplot?

I'm trying to make a world map with a custom legend on the right side. The legend should be with the prepared text on the left and the generated numbers on the right. I tried but to no avail. I need help My code is as follows:
library(dplyr)
library(ggplot2)
library(ggrepel)
library(rworldmap)
world_map_without_antarctica <- getMap()[-which(getMap()$ADMIN=='Antarctica'),] #get data from web
world_map_without_antarctica_t <- fortify(world_map_without_antarctica)
Data <- data.frame( "lon"=c(17.816883, 38.544239,20.895352,20.819651,35.392102,99.060241,
43.756911, 10.288485, 16.566191, 14.076159,8.118301,16.596266,
121.544442,-73.077732,14.938152),
"lat"=c(44.1807678, 35.0126143, 42.5793648, 44.2330372, 38.9907297,
39.5015541, 33.0368223, 51.1337227, 45.0162344, 47.6139488,
46.7917377, 62.8114850, 15.7509443, 3.9272139, 46.1254221),
"NAME"=c("Bosnia and Herzegovina", "Syria", "Kosovo","Republic of Serbia",
"Turkey","United States of America","Iraq","Germany","Croatia",
"Austria","Switzerland","Sweden","Philippines","Colombia","Slovenia"),
"Count"=c(65800,32636,15005,9276,6979,6528,6449,
5830,4862,3109,2959,2777,2577,2315,1394))
Data$label <- paste0(Data$NAME,': ',Data$Count)
word_data_merged <- merge(world_map_without_antarctica_t, Data[ , c("NAME","Count")], by.x="id", by.y="NAME", all.x=T)
word_data_merged <- word_data_merged %>% arrange(id, order)
country_shapes <- geom_polygon(data = world_map_without_antarctica_t, aes(x = long, y = lat, group = group),fill = NA)
maptheme <-
theme(panel.grid = element_blank())+
theme(axis.text = element_blank())+
theme(axis.ticks = element_blank())+
theme(axis.title = element_blank())+
theme(legend.position = "bottom")+
theme(panel.grid = element_blank())+
theme(plot.margin = unit(c(0, 0, 0.5, 0), 'cm'))
guide = guide_colorbar(
title="legend_title",
label = TRUE,
draw.ulim = TRUE,
draw.llim = TRUE,
frame.colour = "black",
ticks = TRUE,
nbin = 10,
label.position = "bottom",
barwidth = 13,
barheight = 1.3,
direction = 'horizontal')
ggplot(word_data_merged) +
labs(title = "plot_title", subtitle = "plot_subtitle") +
country_shapes +
scale_fill_gradient(high = "#381802", low = "#fccaa7", guide = guide) +
geom_polygon(aes(long, lat, group = group, fill=Count),alpha=1) +
geom_point(data=Data[Data$label !="",],aes(x = lon, y = lat), shape = 21,fill= "#275083", color = "#275083", size = 1.5,alpha=0.5) +
geom_path(aes(x=long,y=lat, group = group), color="#c7c9c9", size= 0.5, alpha=0.4) +
geom_label_repel(data=Data,aes(x= lon,y= lat,label = label),
size = 5,
show.legend= F,
fontface = "bold",
point.padding = unit(0.2, "lines") ) +
maptheme +
theme(panel.background = element_rect(fill = "#ebf2f7"))
After running the code, the following world map is obtained:
How can I add a legend with free text entry? I would like the map to look like in this picture:
This might help:
a) changing plot.margin,
b) adding geom_text for the annotation (updated with #Tung's suggestion to use check_overlap = TRUE to sharpen up the text), and
c) coord_cartesian(clip = 'off') to allow drawing outside of the plot area
ggplot(word_data_merged) +
labs(title = "plot_title", subtitle = "plot_subtitle") +
country_shapes +
scale_fill_gradient(high = "#381802", low = "#fccaa7", guide = guide) +
geom_polygon(aes(long, lat, group = group, fill=Count),alpha=1) +
geom_point(data=Data[Data$label !="",],aes(x = lon, y = lat), shape = 21,fill= "#275083", color = "#275083", size = 1.5,alpha=0.5) +
geom_path(aes(x=long,y=lat, group = group), color="#c7c9c9", size= 0.5, alpha=0.4) +
geom_label_repel(data=Data,aes(x= lon,y= lat,label = label),
size = 5,
show.legend= F,
fontface = "bold",
point.padding = unit(0.2, "lines") ) +
geom_text(aes(label = "Statistics", x = 180, y = 80),
fontface = "bold",
hjust = -0.5,
size = 5,
check_overlap = TRUE) +
geom_text(aes(label = "Total unique countries = #", x = 180, y = 70),
hjust = -0.35,
size = 3,
check_overlap = TRUE) +
coord_cartesian(clip = 'off')+
maptheme +
theme(panel.background = element_rect(fill = "#ebf2f7"),
plot.margin = unit(c(0, 4, 0.5, 0), 'cm'))
#> Warning: ggrepel: 12 unlabeled data points (too many overlaps). Consider
#> increasing max.overlaps
Based on: ggplot2 - annotate outside of plot
Created on 2021-01-16 by the reprex package (v0.3.0)

Can this type of plot be done with ggplot2?

I am using R and ggplot2 to do some plots for publishing purposes. I have come across this plot and I would like to replicate it using ggplot2. However, I have never seen a plot like this made using ggplot2.
Can it be done with ggplot2? What about the text below the bars? I guess these will have to be hard coded in the ggplot2 codes. And how do you align those text?
This gets fairly close:
# Generate sample data (I'm too lazy to type out the full labels)
df <- data.frame(
perc = c(60, 36, 44, 41, 42, 57, 34, 52),
type = rep(c("blue", "green"), 4),
label = rep(c(
"Individual reports created as needed",
"Regular reports on single topics",
"Analytics using data integrated from multiple systems",
"Business unit-specific dashboards and visuals"), each = 2))
library(ggplot2)
ggplot(df, aes(1, perc, fill = type)) +
geom_col(position = "dodge2") +
scale_fill_manual(values = c("turquoise4", "forestgreen"), guide = FALSE) +
facet_wrap(~ label, ncol = 1, strip.position = "bottom") +
geom_text(
aes(y = 1, label = sprintf("%i%%", perc)),
colour = "white",
position = position_dodge(width = .9),
hjust = 0,
fontface = "bold") +
coord_flip(expand = F) +
theme_minimal() +
theme(
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
strip.text = element_text(angle = 0, hjust = 0, face = "bold"))
A few explanations:
We use dodged bars and matching dodged labels with position = "dodge2" (note that this requires ggplot_ggplot2_3.0.0, otherwise use position = position_dodge(width = 1.0)) and position = position_dodge(width = 0.9), respectively.
We use facet_wrap and force a one-column layout; strip labels are moved to the bottom.
We rotate the entire plot with coord_flip(expand = F), where expand = F ensures that left aligned (hjust = 0) facet strip texts align with 0.
Finally we tweak the theme to increase the overall aesthetic similarity.
You can try using the data from the other answer. Differences are: we use scales::percent to draw percents. We use ggpubr::theme_transparent() theme to tweak as less as possible.
df$perc <- c(.60, .36, .44, .41, .42, .57, .34, .52)
ggplot(df, aes(label, perc, label=scales::percent(round(perc,2)),fill= factor(type))) +
geom_col(position = position_dodge(0.9), show.legend = F) +
geom_text(aes(y=0), position = position_dodge(0.9), size=5, hjust=-0.1, color="white", fontface="bold") +
scale_y_continuous("",labels = scales::percent) +
coord_flip(expand = F) +
facet_wrap(~label,scales = "free", strip.position = "bottom", ncol = 1) +
ggpubr::theme_transparent() +
xlab("") +
theme(strip.background = element_blank(),
strip.text = element_text(size = 12, face = "bold",hjust=0))
Maybe using facet wrap and adjusting the style?
dat <- data.frame(perc = c(60, 20, 90, 30), col = rep(c("gr1", "gr2"), 2),
text = c(rep("text1", 2), rep("text2", 2)))
ggplot(dat, aes(y = perc, x = col, fill = col)) +
geom_bar(stat = "identity", position = "dodge") +
coord_flip() +
facet_wrap(~text, strip.position = "bottom", ncol = 1)

Resources