duplicating and edit a discrete axis in ggplot2 - 2021 - r

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)
)

Related

How to change items in a ggplot2 legend?

I am trying to change the legend items of this plot.
My code is:
library(ggplot2)
library(HDInterval)
library(ggridges)
df <- data.frame(
density = c(rgamma(400, 2, 10), rgamma(400, 2.25, 9), rgamma(400, 5, 7)),
source = rep(c("source_1", "source_2", "source_3"),
each = 400))
ggplot(df, aes(x = density, color = source, linetype = source,
fill = after_stat(ifelse(quantile == 2, NA, color)))) +
geom_density_ridges_gradient(aes(y = 0), quantile_lines = TRUE, size=1.2,
quantile_fun = hdi, # vline_linetype = 0, scale = 1) +
labs(y = "Density", x = "Contribution") +
scale_linetype_cyclical(name = "Source", values = c("solid", "dotted", "longdash"),
labels = c("source1", "source2", "source3"),
guide = "legend") +
scale_fill_cyclical(name = "Source", values = c("#31a354", "#2c7fb8", "#d95f0e"),
labels = c("source1", "source2", "source3"),
guide = "none", na.value = "transparent") +
scale_color_cyclical(name = "Source", values = c("#31a354", "#2c7fb8", "#d95f0e"),
labels = c("source1", "source2", "source3"),
guide = "none") +
ylim(0, 8) + xlim(0, 1) +
theme(#legend.position=c(.85,.75),
legend.text = element_text(size=16), # item legend text font size
legend.title=element_text(size=18), # title font size
legend.key.height= unit(1, 'cm'),# box height
legend.key.width= unit(1, 'cm')) + # box width
guides(color = guide_legend(override.aes = list(fill = "white")))+
theme(axis.text.y = element_text(size = 12, vjust = 0.5),
axis.text.x = element_text(size = 12, vjust = 0.5),
axis.title.x = element_text(size = 14),
axis.title.y = element_text(size = 14))
I would like to show lines in the legend, instead of the boxes.
I would appreciate your help.
I have tried to understand ggridges deeply, however it is a bit different or rigid for some things.
Thanks in advance.
ggplot(df, aes(x = density, color = source, linetype = source,
fill = after_stat(ifelse(quantile == 2, NA, color)))) +
geom_density_ridges_gradient(aes(y = 0), size=1.2,
quantile_lines = TRUE, quantile_fun = hdi,
key_glyph = "path") +
...
https://ggplot2.tidyverse.org/reference/draw_key.html

ggplot poinstrange with multiple categories - change fill color

I have the following plot:
ggplot() +
geom_pointrange(data=data_FA, mapping=aes(x=snr, y=median, ymin=p25, ymax=p75, colour=factor(method), group=method), position = pd) +
geom_hline(yintercept=FA_GT, linetype="dashed", color = "blue") +
theme(legend.title = element_blank(), legend.position = "none", panel.border = element_rect(colour = "gray", fill=NA, size=1),
plot.margin = unit( c(0,0.5,0,0) , units = "lines" )) +
labs( title = "", subtitle = "")
obtained from the following dataset:
For each group (red and blue) codified by the factor method, I want to see red/blue dots and lines with different transparency according to the factor subset. Does anyone know how to do that? In addition, how can I add more separation space between the two groups (red and blue)?
Thank you!
You can just map alpha to subset inside aes:
ggplot(data_FA) +
geom_pointrange(aes(snr, median, ymin = p25, ymax = p75,
colour = factor(method), group = method,
alpha = subset),
position = pd) +
geom_hline(yintercept = FA_GT, linetype = "dashed", color = "blue") +
scale_alpha_manual(values = c(0.3, 1)) +
theme_bw() +
theme(legend.position = 'none',
panel.border = element_rect(colour = "gray", fill = NA, size = 1),
plot.margin = unit( c(0,0.5,0,0), units = "lines" )) +
labs(title = "", subtitle = "")
Data
data_FA <- data.frame(X = c("X1", "X1.7", "X1.14", "X1.21"),
snr = "snr10",
subset = c("full", "full", "subset5", "subset5"),
method= c("sc", "trunc", "sc", "trunc"),
median = c(0.4883985, 0.4883985, 0.4923685, 0.4914260),
p25 = c(0.4170183, 0.4170183, 0.4180174, 0.4187472),
p75 = c(0.5617713, 0.5617713, 0.5654203, 0.5661565))
FA_GT <- 0.513
pd <- position_dodge2(width = 1)

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

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)

R ggridges plot - Showing y axis ticks and labels

I am trying to generate overlay density plots over time, comparing densities of males vs. females. Here is my output:
I am following the Australian athletes height example from https://cran.r-project.org/web/packages/ggridges/vignettes/gallery.html.
Here is my code:
ggplot(math_dat, aes(x = order_math, y = time, color = gender, point_color = gender, fill = gender)) +
geom_density_ridges(
jittered_points = TRUE, scale = .95, rel_min_height = .01,
point_shape = "|", point_size = 3, size = 0.25,
position = position_points_jitter(height = 0)
) +
scale_y_discrete(expand = c(0, 0)) +
scale_x_continuous(expand = c(0, 0), name = "Rankings") +
scale_fill_manual(values = c("#D55E0050", "#0072B250"), labels = c("female", "male")) +
scale_color_manual(values = c("#D55E00", "#0072B2"), guide = "none") +
scale_discrete_manual("point_color", values = c("#D55E00", "#0072B2"), guide = "none") +
coord_cartesian(clip = "off") +
guides(fill = guide_legend(
override.aes = list(
fill = c("#D55E00A0", "#0072B2A0"),
color = NA, point_color = NA)
)
) +
ggtitle("Ranks over time") +
theme_ridges(center = TRUE)
My problem is I am unable to generate any Y axis tick values and the example doesn't display any either. Any ideas how to get Y axis tick marks to display?
Here is some sample data similar to mine:
## generating dataset
order_math<-c(1,2,1,2,3,3,1,2,3,1,2,3)
gender<-c("M","F","M","M","M","F","F","M","F","M","M","F")
time<-c(1,1,2,3,3,2,1,2,3,2,3,1)
sample<-data.frame(order_math,gender,time)
UPdate:
After #Tomasu's suggestions I have updated my code, but it does not run:
ggplot(math_dat, aes(x = order_math, y = time, color = gender, point_color = gender, fill = gender)) +
geom_density_ridges(
jittered_points = TRUE, scale = .95, rel_min_height = .01,
point_shape = "|", point_size = 3, size = 0.25,
position = position_points_jitter(height = 0)
) +
scale_y_reverse(limits = c(1000, 500, 100),expand = c(0, 0)) +
scale_x_continuous(expand = c(0, 0), name = "Rankings") +
scale_fill_manual(values = c("#D55E0050", "#0072B250"), labels = c("female", "male")) +
scale_color_manual(values = c("#D55E00", "#0072B2"), guide = "none") +
scale_discrete_manual("point_color", values = c("#D55E00", "#0072B2"), guide = "none") +
coord_cartesian(clip = "off") +
guides(fill = guide_legend(
override.aes = list(
fill = c("#D55E00A0", "#0072B2A0"),
color = NA, point_color = NA)
)
) +
ggtitle("Ranks over time") +
theme_ridges(center = TRUE)+
theme(
axis.ticks = element_line(size=0.5), # turn ticks back on
axis.ticks.length = grid::unit(5, "pt"), # set length
axis.ticks.y = element_line(colour = "red"), # define tick line color
axis.text.y = element_text(vjust = .4) # center text with tick
)
An easy solution to this problem would be to use a theme_ that includes the axis ticks as theme_ridges() has them turned off. Just removing that theme all together and using the base ggplot2 theme achieves the desired outcome.
However, let's say we still want to use theme_ridges() and just turn ticks back on. This can be achieved with a theme() edit after the theme_ridges().
I'm using the example in the link provided as I couldn't get your sample data to work properly.
library(ggplot2)
library(ggplot2movies)
library(ggridges)
ggplot(movies[movies$year>1912,], aes(x = length, y = year, group = year)) +
geom_density_ridges(scale = 10, size = 0.25, rel_min_height = 0.03) +
theme_ridges() +
theme(
axis.ticks = element_line(size=0.5), # turn ticks back on
axis.ticks.length = grid::unit(5, "pt"), # set length
axis.ticks.y = element_line(colour = "red"), # define tick line color
axis.text.y = element_text(vjust = .4) # center text with tick
) +
scale_x_continuous(limits = c(1, 200), expand = c(0, 0)) +
scale_y_reverse(
breaks = c(2000, 1980, 1960, 1940, 1920, 1900),
expand = c(0, 0)
) +
coord_cartesian(clip = "off")
Created on 2021-05-11 by the reprex package (v1.0.0)
I think your problem is that you need to specify the group.
Related thread: geom_density_ridges requires the following missing aesthetics: y
Extending on code from user tomasu's answer +1
library(ggridges)
library(ggplot2)
order_math<-c(1,2,1,2,3,3,1,2,3,1,2,3)
gender<-c("M","F","M","M","M","F","F","M","F","M","M","F")
time<-c(1,1,2,3,3,2,1,2,3,2,3,1)
sample<-data.frame(order_math,gender,time)
ggplot(sample, aes(x = order_math, y = time, group = time,
color = gender, point_color = gender, fill = gender)) +
geom_density_ridges() +
theme(
axis.ticks = element_line(size=0.5), # turn ticks back on
axis.ticks.length = grid::unit(5, "pt"), # set length
axis.ticks.y = element_line(colour = "red"), # define tick line color
axis.text.y = element_text(vjust = .4) # center text with tick
)
#> Picking joint bandwidth of 0.555
Created on 2021-05-12 by the reprex package (v2.0.0)

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)

Resources