Transparent masking in ggplot2 - r

I'm interested in ways to only include panel grid lines right near the ribbon--I can do this manually, in a trivial example
library(ggplot2)
d1 <- data.frame(x = seq(0, 1, length.out = 200))
d1$y1 <- -3*(d1$x-.5)^2 + 1
d1$y2 <- -3*(d1$x-.5)^2 + 2
ggplot(d1) +
geom_ribbon(aes(x, ymin = y1, ymax = y2),
alpha = .25) +
geom_ribbon(aes(x, ymax = y1),
ymin = .25,
fill = "white") +
geom_ribbon(aes(x, ymin = y2),
ymax = 2,
fill = "white") +
scale_y_continuous(limits = c(.25, 2.0),
expand = c(0, 0))+
scale_x_continuous(limits = c(0, 1),
expand = c(0, 0))+
theme_bw() +
theme(panel.grid = element_line(linetype = 1, color = "black"))
is there some less hacky way to have a transparent mask for these gridlines, so they only appear underneath a ribbon?

If gridlines the same color as the background are acceptable, you can remove the actual gridlines, then use geom_hline() and geom_vline() to make your own "gridlines" that will show on ribbons but be invisible against the background
d1$y3 <- d1$x + 0.3
d1$y4 <- d1$x + 0.4
ggplot(d1) +
geom_ribbon(aes(x, ymin = y1, ymax = y2), alpha = 0.25) +
geom_ribbon(aes(x, ymin = y3, ymax = y4), alpha = 0.25, fill = "blue") +
# use geom_vline and geom_hline to plot "gridlines" on top of ribbons
geom_hline(yintercept = seq(0, 2, by = 0.25), colour = "white") +
geom_vline(xintercept = seq(0, 1, by = 0.25), colour = "white") +
scale_y_continuous(limits = c(.25, 2.0), expand = c(0, 0)) +
scale_x_continuous(limits = c(0, 1), expand = c(0, 0)) +
theme_bw() +
theme(panel.grid.minor = element_blank(), # remove actual gridlines
panel.grid.major = element_blank())
produces this:
This is still a workaround, and will only make gridlines that match the background color, but it is easy to use with a variety of plots, such as the situation you mentioned with multiple ribbons (I've added a second ribbon to demonstrate that this will work)

Related

Trying to add legend using geom_abline

I have a data frame, saved as df, with two columns of points that I would like to plot. In addition, I would like to plot two lines on the plot and would like to have a legend for these lines. Here is my code:
ggplot(df, aes(x = x, y = y)) +
geom_point(color = "black", shape = 16, alpha = 1) +
scale_x_continuous(name = "x", limits = c(-5, 5)) +
scale_y_continuous(name = "y", limits = c(-5, 5)) +
geom_abline(intercept = 0, slope = 4/3, linetype = "dashed",
color = "gray40", size = 1, aes(colour = "XNULL")) +
geom_abline(intercept = 0, slope = 0, linetype = "dotted",
color = "gray40", size = 1, aes(colour = "YNULL")) +
scale_color_manual(name = "", values = c("XNULL" = "red", "YNULL" = "blue")) +
theme(panel.background = element_rect(fill = "white"),
panel.border = element_rect(colour = "black", fill = NA, size = 1),
legend.position = "bottom")
However, when I run this, no legend comes up (I would like to have the legend on the bottom). Any suggestions as to what I am doing wrong? I am new at using ggplot2, and none of the solutions I looked up on other forums helped.
You can try creating another data.frame to contain information about your ablines:
df = data.frame(x=runif(10),y=runif(10))
df2 = data.frame(intercept=0,slope=c(4/3,0),type=c("XNULL","YNULL"))
Then we can call geom_abline specifying the aes so that we can use
ggplot(df, aes(x = x, y = y)) +
geom_point(color = "black", shape = 16, alpha = 1) +
scale_x_continuous(name = "x", limits = c(-5, 5)) +
scale_y_continuous(name = "y", limits = c(-5, 5)) +
geom_abline(data=df2,aes(intercept=intercept,slope=slope,
linetype=type,col=type),size = 1) +
scale_color_manual(name = "", values = c("XNULL" = "red", "YNULL" = "blue")) +
scale_linetype_manual(name = "", values = c("XNULL" = "dashed", "YNULL" = "dotted")) +
theme(panel.background = element_rect(fill = "white"),
panel.border = element_rect(colour = "black", fill = NA, size = 1),
legend.position = "bottom")
From the documentation:
These geoms act slightly differently from other geoms. You can supply
the parameters in two ways: either as arguments to the layer function,
or via aesthetics. If you use arguments, e.g. geom_abline(intercept =
0, slope = 1), then behind the scenes the geom makes a new data frame
containing just the data you've supplied.
Apparently, you have to specify intercept and slope in aes, so that it works.
library(ggplot2)
ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) +
geom_point() +
coord_cartesian(xlim = c(0,10), ylim = c(0,10)) +
geom_abline(aes(intercept = 0, slope = 0, color = "X"), linetype = "dotted") +
geom_abline(aes(intercept = 0, slope = 4/3, color = "Y"),linetype = "dashed") +
scale_color_manual(values = c(X = 'grey', Y = 'black'))
Created on 2020-02-12 by the reprex package (v0.3.0)

How to surpress horizontal grid lines without removing ticks from y axis?

I want to remove horizontal grid lines but keep vertical ones. I also want to keep ticks on both x and y axis.
This is my code and what I tried so far:
df <- data.frame("prop" = c(102.73,260.65), "Name" = c("All Genes","RG Genes"))
p<-ggplot(data=df, aes(x=Name, y=prop,fill=Name)) +
geom_bar(stat="identity")+
labs(x="", y = "Proportion of cis EQTLs")+
scale_fill_brewer(palette="Greens") +
theme_minimal()+
theme(legend.position = "none",panel.grid.minor.y = element_blank())
p + annotate("text", x = 1.5, y = 280, label = "p = XXXXXX", size = 3.5) +
annotate("rect", xmin = 1, xmax = 2, ymin = 270, ymax =270, alpha=1,colour = "black")
You were 95% of the way there. The grid has two sets of lines--major and minor. You removed half of the horizontal grid (panel.grid.minor.y). To remove the other half add panel.grid.major.y = element_blank(). To add ticks to both the x and y axis add axis.ticks = element_line()
df <- data.frame("prop" = c(102.73,260.65), "Name" = c("All Genes","RG Genes"))
p <- ggplot(data = df, aes(x = Name, y = prop, fill = Name)) +
geom_bar(stat = "identity") +
labs(x = "", y = "Proportion of cis EQTLs") +
scale_fill_brewer(palette="Greens") +
theme_minimal() +
theme(legend.position = "none",
panel.grid.major.y = element_blank(),
panel.grid.minor.y = element_blank(),
axis.line = element_line(),
axis.ticks = element_line())
p + annotate("text", x = 1.5, y = 280, label = "p = XXXXXX", size = 3.5) +
annotate("rect", xmin = 1, xmax = 2, ymin = 270, ymax =270, alpha=1,colour = "black")

Add space above y-axis without expand()

When plotting percentages and a column is at 100%, the value label gets cut of from the graph.
Two possible solutions to this are:
1. scale_y_continuous(limits = c(0, 1.1)
2. scale_y_continuous(expand = c(0, 0, 0.2, 0)
But both solutions expand the axis. I would prefer to just add a padding/margin so that I don't get a long line above 100%. Is this possible?
Working example
library(ggplot2)
library(magrittr)
data.frame("value" = c(0, 0.5, 1),
"v1" = letters[1:3]) %>%
ggplot(aes(x = v1,
y = value,
label = value)) +
geom_bar(stat = "identity") +
geom_text(stat = "identity",
vjust = -1) +
scale_y_continuous(breaks = seq(0, 1, 0.2),
limits = c(0, 1),
labels = scales::percent,
expand = c(0, 0, 0.2, 0)) +
theme_classic()
You can pad the plot with plot.margin argument in the theme function and turn off clipping in coord_cartesian to allow for drawings to be unconfined to the plot panel.
data.frame("value" = c(0, 0.5, 1),
"v1" = letters[1:3]) %>%
ggplot(aes(x = v1,
y = value,
label = value)) +
geom_bar(stat = "identity") +
geom_text(stat = "identity",
vjust = -1) +
scale_y_continuous(breaks = seq(0, 1, 0.2),
limits = c(0, 1),
labels = scales::percent) +
theme_classic() +
theme(plot.margin = margin(t = 10, unit = "pt")) + ## pad "t"op region of the plot
coord_cartesian(clip = "off")
Probably worth noting as well this is only an issue when you want a wide plot.
An alternate approach is to limit the extension of axes' lines. This is implemented in the package lemon, which also allows you to place square brackets for each tick instead of a single line for the axis:
library(ggplot2)
df <- data.frame("value" = c(0, 0.5, 1),
"v1" = letters[1:3])
p <- ggplot(df, aes(x = v1,
y = value,
label = value)) +
geom_bar(stat = "identity") +
geom_text(stat = "identity",
vjust = -1) +
scale_y_continuous(breaks = seq(0, 1, 0.2),
limits = c(0, 1),
labels = scales::percent,
expand = rep(0,4)) +
theme_classic()
library(lemon)
p + coord_flex_cart(ylim=c(-0.01, 1.1), left=capped_vertical(capped='both', gap=0.0),
bottom = brackets_horizontal())
The length of the brackets can be modified with arguments length and tick.length.

Change geom_text label angle in plotly

I have the following chart I have built using ggplot + ggplotly.
I am trying to add labels to the red (median) and blue (percentile 90%) vertical lines without luck.
Please advise how should I fix it.
The code I have used:
p1 <- ggplot(users_d_total %>% filter(isSame, D_rank == 2), aes(x = D, fill = as.factor(train_user_id))) +
geom_density(alpha = .3) +
labs(title = paste0("Without Normalization Analysis [K = 2]")) +
scale_fill_discrete(name = "Users") +
scale_x_continuous(breaks = by_two) +
geom_vline(aes(xintercept = median(D)), col = 'red', linetype = 1, size = 1) +
geom_text(aes(x = median(D), y = 1, label = "Median"), hjust = 1, angle = 90, colour= "red") +
geom_vline(aes(xintercept = quantile(D, probs = .9)), col = 'blue', linetype = 1, size = 1) +
geom_text(aes(x = quantile(D, probs = .9), y = 1, label = "90th Percentile"), hjust = 1, angle = 90, colour = "blue") +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
ggplotly(p1)
I want the text to be vertical but using the answer from How to add legend for vertical lines in ggplot? didn't help me.

ggplot2: Highlight area depending on dnorm function

I want to highlight the area between a vertical line and a normal distributed function. I know how it works with discrete values, but the stat_function confuses me. The code looks something like this:
library(ggplot2)
n1 <- 5
ggplot(data.frame(x = c(-2, 2)), aes(x)) +
stat_function(fun = dnorm, args = list(sd = 1/sqrt(n1))) +
geom_vline(xintercept = 0.5, linetype = "dashed", color = "red", size = 1) +
geom_vline(xintercept = -0.5, linetype = "dashed", color = "red", size = 1) +
ylim(c(0, 1.5)) +
theme_light() +
geom_rect(aes(xmin = 0.5, xmax = Inf, ymax = Inf, ymin = 0), fill = "grey", alpha = .3)
I know I need to change ymax to the values of x > 0.5. The question is how?
EDIT:
I looked into the question which is supposed to be the same as mine. When I rewrite the code the way they did, the highlighting works but it doesn't give me a proper normal distribution anymore, as you can see here:
library(dplyr)
set.seed(123)
range <- seq(from = -2, to = 2, by = .01)
norm <- rnorm(range, sd = 1 / sqrt(n1))
df <- data_frame(x = density(norm)$x, y = density(norm)$y)
ggplot(data_frame(values = norm)) +
stat_density(aes(x = values), geom = "line") +
geom_vline(xintercept = 0.5, linetype = "dashed", color = "red", size = 1) +
geom_vline(xintercept = -0.5, linetype = "dashed", color = "red", size = 1) +
ylim(c(0, 1.5)) +
theme_light() +
geom_ribbon(data = filter(df, x > 0.5),
aes(x = x, ymax = y), ymin = 0, fill = "red", alpha = .5)
When I stick with stat_function and use geom_ribbon with subsetting as proposed in the very same question, it highlights buggy, as you can see here:
ggplot(data_frame(x = c(-2, 2)), aes(x)) +
stat_function(fun = dnorm, args = list(sd = 1/sqrt(n1))) +
geom_vline(xintercept = 0.5, linetype = "dashed", color = "red", size = 1) +
geom_vline(xintercept = -0.5, linetype = "dashed", color = "red", size = 1) +
ylim(c(0, 1.5)) +
theme_light() +
geom_ribbon(data = filter(df, x > 0.5),
aes(x = x, ymax = y), ymin = 0, fill = "red", alpha = .5)
Not satisfying yet.
Here is an approach:
library(ggplot2)
n1 <- 5
ggplot(data.frame(x = c(-2, 2)), aes(x)) +
stat_function(fun = dnorm, geom = "area", fill = "grey", alpha = 0.3, args = list(sd = 1/sqrt(n1)), xlim = c(-0.5,0.5)) +
stat_function(fun = dnorm, args = list(sd = 1/sqrt(n1))) +
geom_vline(xintercept = 0.5, linetype = "dashed", color = "red", size = 1) +
geom_vline(xintercept = -0.5, linetype = "dashed", color = "red", size = 1) +
ylim(c(0, 1.5)) +
theme_light()
in stat_function one can define different geom, just pick the ones that suits your needs.

Resources