How to add second axis on ggplot? - r

I am doing Manhattan plot for 2 phenotypes and therefore I am melting data for columns GWAS and GTEX in my dataframe which looks like this:
pos.end GWAS GTEX
1 16975756 0.71848040 2.82508e-05
2 16995937 0.02349431 4.54958e-11
3 17001098 0.04310933 1.93264e-20
4 17001135 0.04354486 8.52552e-21
5 17002964 0.02352996 1.84111e-15
6 17005677 0.01046168 2.09734e-11
...
The problem is that GTEX data is much smaller than GWAS so I would need to have two y axis to represent them.
I am suppose to use something like this:
scale_y_continuous(sec.axis = sec_axis...
but I am unsure how to implement that in my case.
right now this is my code:
library(dplyr)
library(ggplot2)
library(tibble)
library(ggrepel)
snpsOfInterest = c("17091307")
tmp = read.table("nerve_both_manh", header=T)
tmp.tidy <- tmp %>%
tidyr::gather(key, value, -pos.end) %>%
mutate(is_highlight = ifelse(pos.end %in% snpsOfInterest, "yes", "no")) %>%
mutate(is_annotate = ifelse(-log10(value) > 5, "yes", "no"))
ggplot(tmp.tidy, aes(pos.end, -log10(value), color = key)) +
geom_point(data = subset(tmp.tidy, is_highlight == "yes"),
color = "purple", size = 2)+
geom_label_repel(data = subset(tmp.tidy, is_annotate == "yes"),
aes(label = pos.end), size = 2)
I need to have 2 Y axis one for GWAS and another one for GTEX. GTEX values are much smaller than those for GWAS.
I plotted with the code above this and it looks like this:
![two muppets][1]
UPDATE
I tired to use locus.zoom() from ggforce library but still results is not good. How do I get just the zoomed GWAS values?
ggplot(tmp.tidy, aes(pos.end, -log10(value), color=key)) +
facet_zoom(xy = key == "GWAS")+
geom_point(data=subset(tmp.tidy, is_highlight=="yes"), color="purple", size=2)+
geom_label_repel( data=subset(tmp.tidy, is_annotate=="yes"), aes(label=pos.end), size=2)
![one muppet][1]
UPDATE
per suggestion bellow I did:
ggplot(tmp.tidy) +
geom_count(aes(pos.end, -log10(value), color = key)) +
facet_wrap(~key, scales = "free") +
guides(size = FALSE) +
theme(
panel.background = element_rect(fill = "white", color = "grey90"),
panel.spacing = unit(2, "lines")
)
But I don't know how to integrate in this these two lines:
geom_point(data=subset(tmp.tidy, is_highlight=="yes"), color="purple", size=2)+
geom_label_repel( data=subset(tmp.tidy, is_annotate=="yes"), aes(label=pos.end), size=2)+
If I use it with the above code I am getting this error:
Error: geom_point requires the following missing aesthetics: x, y
I tried doing it like this but nothing happens:
ggplot(tmp.tidy) +
geom_count(aes(pos.end, -log10(value), color = key)) +
facet_wrap(~key, scales = "free") +
guides(size = FALSE) +
geom_point(data = subset(tmp.tidy, is_highlight == "yes"), aes(x = pos.end, y = -log10(value)),color = "purple", size = 2) +
geom_label_repel(data = subset(tmp.tidy, is_annotate == "yes"), aes(aes(x = pos.end, y = -log10(value), label = pos.end), size = 2)
theme(
panel.background = element_rect(fill = "white", color = "grey90"),
panel.spacing = unit(2, "lines")
)

I tried to approximate your problem with the diamonds dataset. Could you add an identifier in your data and then use facet_wrap() on it?
df <-
diamonds %>%
slice(1:2000) %>%
filter(price < 400 | price > 3000) %>%
mutate(type = ifelse(price < 500 & row_number() < 100, "GWAS", "GTEX"))
ggplot(df) +
geom_count(aes(table, price, color = type)) +
facet_wrap(~type, scales = "free") +
guides(size = FALSE) +
theme(
panel.background = element_rect(fill = "white", color = "grey90"),
panel.spacing = unit(2, "lines")
)
To update your code per the conversation below you would use
geom_point(
data = subset(tmp.tidy, is_highlight == "yes"),
aes(x = pos.end, y = -log10(value)),
color = "purple", size = 2
) +
geom_label_repel(
data = subset(tmp.tidy, is_annotate == "yes"),
aes(x = pos.end, y = -log10(value), label = pos.end),
size = 2
)

Related

R: How specify bars color in barplot?

My dataframe has 2 numerical and categorical columns. Negative Bars are filled with white but with with the same coloured borders as corresponding positive bars.
Now I need to have bars with same colour and B category in different colour
df <- data.frame(model = c("A","B","C","D","B","C"),
category = c("origin", "origin","origin","abroad","abroad","abroad"),
pos = c(40,50,45,100,105,80),
neg = c(-10,-5,-4,-16,-7,-2),
Colour = c("chocolate","deeppink4","yellow","steelblue3","deeppink4","yellow"))
Colour <- as.character(df$Colour)
Colour <- c(Colour,"white")
names(Colour) <- c(as.character(df$model),"white")
df <- df %>% pivot_longer(., cols=c('pos','neg'),
names_to = 'sign') %>%
mutate(Groups = paste(category, model),
sign = factor(sign, levels = c("neg", "pos")))
ggplot() +
# plot positive with fill and colour based on model
geom_col(aes(value, tidytext::reorder_within(model, value, category),
fill = model, color = model),
data = df[df$sign == "pos", ],
position = "stack") +
# plot negative with colour from based on model, but fill fixed as "white"
geom_col(aes(value, tidytext::reorder_within(model, value, category),
color = model),
data = df[df$sign == "neg", ],
fill = "white",
position = "stack") +
# the rest is same as OP's code
tidytext::scale_y_reordered() +
labs(fill = "model") +
facet_grid(category ~ ., switch = "y",scales = "free_y") +
theme(axis.text.x = element_text(angle = 90),
strip.background = element_rect(fill = "white"),
strip.placement = "outside",
strip.text.y.left = element_text(angle = 0),
panel.spacing = unit(0, "lines")) +
theme(legend.position="none") +
labs( title = "BarPlot",
subtitle = "changes",
y = " ")
Original output
Expected output:
I've added mod_col to the df so B's green and everything else purple. Then used mod_col for the fill and colour in the geom_s. And added scale_*_identity to use those colours.
library(tidyverse)
df <- data.frame(model = c("A","B","C","D","B","C"),
category = c("origin", "origin","origin","abroad","abroad","abroad"),
pos = c(40,50,45,100,105,80),
neg = c(-10,-5,-4,-16,-7,-2),
Colour = c("chocolate","deeppink4","yellow","steelblue3","deeppink4","yellow")
)
# Colour <- as.character(df$Colour)
# Colour <- c(Colour,"white")
# names(Colour) <- c(as.character(df$model),"white")
df <- df %>% pivot_longer(., cols=c('pos','neg'),
names_to = 'sign') %>%
mutate(Groups = paste(category, model),
sign = factor(sign, levels = c("neg", "pos")),
mod_col = if_else(model == "B", "green", "purple"))
ggplot() +
# plot positive with fill and colour based on model
geom_col(aes(value, tidytext::reorder_within(model, value, category),
fill = mod_col, color = mod_col),
data = df[df$sign == "pos", ],
position = "stack") +
# plot negative with colour from based on model, but fill fixed as "white"
geom_col(aes(value, tidytext::reorder_within(model, value, category),
color = mod_col),
data = df[df$sign == "neg", ],
fill = "white",
position = "stack") +
# the rest is same as OP's code
scale_fill_identity() +
scale_colour_identity() +
tidytext::scale_y_reordered() +
labs(fill = "model") +
facet_grid(category ~ ., switch = "y",scales = "free_y") +
theme(axis.text.x = element_text(angle = 90),
strip.background = element_rect(fill = "white"),
strip.placement = "outside",
strip.text.y.left = element_text(angle = 0),
panel.spacing = unit(0, "lines")) +
theme(legend.position="none") +
labs( title = "BarPlot",
subtitle = "changes",
y = " ")
Created on 2022-06-02 by the reprex package (v2.0.1)

How to automatically change label color depending on relative values (maximum/minimum)?

In order to make a dynamic visualization, for example in a dashboard, I want to display the label colors (percentages or totals) depending on their real values in black or white.
As you can see from my reprex below, I changed the color of the label with the highest percentage manually to black, in order gain a better visability.
Is there a was, to automatically implement the label color? The label with the highest percentage corresponding should always be black, if data is changing over time.
library(ggplot2)
library(dplyr)
set.seed(3)
reviews <- data.frame(review_star = as.character(sample.int(5,400, replace = TRUE)),
stars = 1)
df <- reviews %>%
group_by(review_star) %>%
count() %>%
ungroup() %>%
mutate(perc = `n` / sum(`n`)) %>%
arrange(perc) %>%
mutate(labels = scales::percent(perc))
ggplot(df, aes(x = "", y = perc, fill = review_star)) +
geom_col(color = "black") +
geom_label(aes(label = labels), color = c( "white", "white","white",1,"white"),
position = position_stack(vjust = 0.5),
show.legend = FALSE) +
guides(fill = guide_legend(title = "Answer")) +
scale_fill_viridis_d() +
coord_polar(theta = "y") +
theme_void()
you can set the colors using replace(rep('white', nrow(df)), which.max(df$perc), 'black').
ggplot(df, aes(x = "", y = perc, fill = review_star)) +
geom_col(color = "black") +
geom_label(aes(label = labels),
color = replace(rep('white', nrow(df)), which.max(df$perc), 'black'),
position = position_stack(vjust = 0.5),
show.legend = FALSE) +
guides(fill = guide_legend(title = "Answer")) +
scale_fill_viridis_d() +
coord_polar(theta = "y") +
theme_void()

ggplot2 legend points not coloured correctly

My ggplot2 legend is not colouring correctly - it is appearing in all black rather than the colours of my plot. I have reproduced this error in the iris dataset.
iris <- iris %>%
mutate(
Size = case_when(
`Sepal.Length` < 5.4 ~ "Small",
`Sepal.Length` > 5.4 ~ "Big"
))
iris_mapping <- aes_string(
fill = paste0("`Species`"),
shape = paste0("`Size`")
)
my_plot <-
ggplot(iris,
aes_string(
x = paste0("`Petal.Length`"),
y = paste0("`Petal.Width`"))) +
geom_point(iris_mapping,
size = 4, alpha = 0.9, color = "black") +
theme_bw() +
theme(
plot.title = element_text(hjust = 0.5),
legend.text = element_text(family = "mono", face = "bold")) +
scale_fill_manual(
values = fgplots::brew_fg_colors(length(unique(iris$Species))),
name = "Species") +
scale_shape_manual(name = "Size",
values = c(21, 22))+
xlab("`Petal.Length`") +
ylab("`Petal.Width`")
Does anyone know why this is happening / how I can get the legend colour to match the plot colouring?

Include 2nd variable labels on an existing Variable vs sample plot geom_jitter

I have a geom_jitter plot showing Variables between 2 samples, I would like to include the Group-variable parameters on the left of the plot, setting a separation by lines like in the figure below. Thus, Variables are organised by Group.
Here is a reproducible example:
data<- tibble::tibble(
Variable = c("A","B","C","D","E", "F"),
Group = c("Asia","Asia","Europe","Europe","Africa","America"),
sample1 = c(0.38,0.22,0.18,0.12,0.1,0),
sample2 = c(0.23,0.2,0,0.12,0.11,0.15))
library(reshape2)
data2<- melt(data,
id.vars=c("Variable", "Group"),
measure.vars=c("sample1", "sample2"),
variable.name="Sample",
value.name="value")
data22[is.na(data22)] <- 0
library(ggplot2)
ggplot(data2, aes(x = Sample, y = Variable, label=NA)) +
geom_point(aes(size = value, colour = value)) +
geom_text(hjust = 1, size = 2) +
# scale_size(range = c(1,3)) +
theme_bw()+
scale_color_gradient(low = "lightblue", high = "darkblue")
Here is the current output I have:
And this is the format I would like:
To get a polished version of the plot most similar to your ideal plot, you can use facet_grid() plus some theme() customization.
ggplot(data2, aes(x = Sample, y = Variable, label=NA)) +
geom_point(aes(size = value, colour = value)) +
geom_text(hjust = 1, size = 2) +
# scale_size(range = c(1,3)) +
theme_bw()+
scale_color_gradient(low = "lightblue", high = "darkblue") +
facet_grid(Group~., scales = "free", switch = "y") +
theme(strip.placement = "outside",
strip.text.y = element_text(angle = 180),
panel.spacing = unit(0, "cm"))

heatmap in ggplot, different color for each group

I am trying to produce a heatmap in ggplot. I want each group to have different color gradient, but don't know how to do that. My current code looks like this:
## dummy data -----------------------------------------------------------------------------
data <- data.frame(
group = sample(c("Direct Patient Care", "Indirect Patient Care", "Education", "Rounds", "Handoff", "Misce"), 30, replace = T),
pct = rnorm(30, mean = 50, sd = 8)
)
## generate group id
data <- data %>%
group_by(group) %>%
mutate(id = row_number())
data$grpid <- with(data, ifelse(group == "Direct Patient Care", 1, ifelse(group == "Indirect Patient Care", 2,
ifelse(group == "Education", 3,
ifelse(group == "Rounds", 4,
ifelse(group == "Handoff", 5,6 ))))))
## draw graph ------------------------------------------------------------------------------
library(ggplot2)
p <- ggplot(data, aes(x=id, y=group, fill = pct)) +
theme(panel.background = element_rect(fill = "white", colour = "grey50"), aspect.ratio = 0.4) +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank()
)+
# guides(fill = guide_legend("Time, %")) +
geom_tile() +
scale_x_continuous (name = " ", breaks = seq(1, 8, by = 1)) +
scale_y_discrete(name = " ") +
theme(axis.text.x = element_text(angle = 0,hjust = 1,vjust = 1), plot.title = element_text(hjust = 0.5) ) +
ggtitle("Heatmap of time spent doing activities across 194 shifts")
p + scale_fill_gradient2(low = "white", high = "red", limits = c(0, 80), breaks = c(0, 10, 20, 30, 40, 50, 60, 70), guide = guide_legend("Time, %")) ## change the color theme ##
And the resulting figure looks like this:
How can I change the color theme for each group, like red for 'Rounds', blue for 'Misce', green for 'Handoff' etc...
Many thanks!
You can do this by creating your own rescaled value in your data and then slightly "hacking" the alpha aesthetic combined with the fill aesthetic:
library(tidyverse)
data %>%
group_by(group) %>%
mutate(rescale = scales::rescale(pct)) %>%
ggplot(., aes(x = factor(id), y = group)) +
geom_tile(aes(alpha = rescale, fill = group), color = "white") +
scale_alpha(range = c(0.1, 1))
First we create a new column called rescale which rescales the pct from 0 to 1 then you force the scale_alpha(range = c(0, 1)) [note, in this case I used c(0.1, 1) so that you can still "see" the zero points.
Finally, you probably want to remove the guides:
data %>%
group_by(group) %>%
mutate(rescale = scales::rescale(pct)) %>%
ggplot(., aes(x = factor(id), y = group)) +
geom_tile(aes(alpha = rescale, fill = group), color = "white") +
scale_alpha(range = c(0.1, 1)) +
theme(legend.position = "none")
N.B. by using aes(x = factor(id)... you can get around manually setting your x-axis since in this case it appears you want to treat it as a factor not a numeric scale.
Finally, if you really want to get fancy, you could double-encode the axis.text.y colors to that of the levels of your factor (i.e., data$group) variable:
data %>%
group_by(group) %>%
mutate(rescale = scales::rescale(pct)) %>%
ggplot(., aes(x = factor(id), y = group)) +
geom_tile(aes(alpha = rescale, fill = group), color = "white") +
scale_alpha(range = c(0.1, 1)) +
theme(legend.position = "none",
axis.text.y = element_text(color = scales::hue_pal()(length(levels(data$group)))),
axis.ticks = element_blank()) +
labs(x = "", y = "")

Resources