Plot coloured boxes around axis label - r

Consider this simple example
library(tidyverse)
tibble(x = as.factor(c('good', 'neutral', 'bad')),
y = as.factor(c('bad', 'neutral', 'bad'))) %>%
ggplot(aes(x = x, y = y)) + geom_point()
I would like to put the x labels (good, neutral, bad) in different colored boxes. For instance, good (on both the x and y axis) would be surrounded on a small green box, and so on.
Can I do that in ggplot2?

Like this?
tibble(x = as.factor(c('good', 'neutral', 'bad')),
y = as.factor(c('bad', 'neutral', 'bad'))) %>%
ggplot(aes(x = x, y = y)) +
geom_point() +
theme(axis.text.x = element_text(color = c('red', 'blue', 'green')))
Your Plot:
EDIT
An alternate pretty Ghetto solution using grid
tibble(x = as.factor(c('good', 'neutral', 'bad')),
y = as.factor(c('bad', 'neutral', 'bad'))) %>%
ggplot(aes(x = x, y = y)) +
geom_point()
grid::grid.polygon(x = c(.3,.3,.25,.25), y = c(.07,.04,.04,.07),gp = gpar(col = 'green', fill = 'green', alpha = .5))
grid::grid.polygon(x = c(.525,.525,.575,.575), y = c(.07,.04,.04,.07),gp = gpar(col = 'red', fill = 'red', alpha = .5))
grid::grid.polygon(x = c(.79,.79,.86,.86), y = c(.07,.04,.04,.07),gp = gpar(col = 'blue', fill = 'blue', alpha = .5))

Solution using geom_label outside the plot area:
ggplot(data, aes(x, y)) +
geom_point() +
geom_label(aes(0.3, y, label = y, fill = y), hjust = 0) +
geom_label(aes(x, 0.45, label = x, fill = x)) +
theme_minimal() +
theme(
axis.text = element_blank(),
axis.ticks = element_blank(),
legend.position = "none"
) +
coord_cartesian(xlim = c(1, 3), ylim = c(1, 2), clip = "off")
Another solution
You should create geom_rect with borders, but without fill and plot them outside the plot area (using coord_cartesian):
library(tidyverse)
data <- tibble(
x = as.factor(c('good', 'neutral', 'bad')),
y = as.factor(c('bad', 'neutral', 'bad'))
)
ggplot(data, aes(x, y)) +
geom_point() +
# put rects on y-axis
geom_rect(aes(xmin = 0.1, xmax = 0.45, color = y,
ymin = as.numeric(y) - 0.1, ymax = as.numeric(y) + 0.1),
fill = NA, size = 3) +
# put rects on x-axis
geom_rect(aes(ymin = 0.3, ymax = 0.4, color = x,
xmin = as.numeric(x) - 0.15, xmax = as.numeric(x) + 0.15),
fill = NA, size = 3) +
# Here it's important to specify that your axis goes from 1 to max number of levels
coord_cartesian(xlim = c(1, 3), ylim = c(1, 2), clip = "off")

Another approach
Create a vector of colors and pass them into axis.text.x() option of theme().
# data
x = as.factor(c('good', 'neutral', 'bad'))
y = as.factor(c('bad', 'neutral', 'bad'))
df<- data.frame(x,y)
# create a vector of colors
mycolors<- c("red","blue","green")
library(ggplot2)
ggplot(df, aes(x = x, y=y))+
geom_point()+
theme(axis.text.x = element_text(colour = mycolors))

One approach could be this:
tibble(x = as.factor(c('good', 'neutral', 'bad')),
y = as.factor(c('bad', 'neutral', 'bad'))) %>%
ggplot(aes(x = x, y = y)) + geom_point()+
geom_rect(aes(xmin=0.5, xmax=1.5, ymin=-Inf, ymax=Inf), fill="red", alpha=0.1)+
geom_rect(aes(xmin=1.5, xmax=2.5, ymin=-Inf, ymax=Inf), fill="yellow", alpha=0.1)+
geom_rect(aes(xmin=2.5, xmax=3.5, ymin=-Inf, ymax=Inf), fill="green", alpha=0.1)
With geom_rect() you can add colored backgrounds:

Related

Adjust background alpha of geom_richtext

I have below ggplot (from https://wilkelab.org/ggtext/reference/geom_richtext.html)
library(ggplot2)
df <- data.frame(
label = c(
"Some text **in bold.**",
"Linebreaks<br>Linebreaks<br>Linebreaks",
"*x*<sup>2</sup> + 5*x* + *C*<sub>*i*</sub>",
"Some <span style='color:blue'>blue text **in bold.**</span><br>And *italics text.*<br>
And some <span style='font-size:18pt; color:black'>large</span> text."
),
x = c(.2, .1, .5, .9),
y = c(.8, .4, .1, .5),
hjust = c(0.5, 0, 0, 1),
vjust = c(0.5, 1, 0, 0.5),
angle = c(0, 0, 45, -45),
color = c("black", "blue", "black", "red"),
fill = c("cornsilk", "white", "lightblue1", "white")
)
ggplot(df) +
aes(
x, y, label = label, angle = angle, color = color, fill = fill,
hjust = hjust, vjust = vjust
) +
geom_richtext() +
geom_point(color = "black", size = 2) +
scale_color_identity() +
scale_fill_identity() +
xlim(0, 1) + ylim(0, 1)
I would like to add some transparency to the label background. When I apply alpha = 0.30, both text and background are affected. I there any way to adjust alpha of background?
#stefan suggested to use scales::alpha, however this is not working in below case
library(ggplot2)
library(ggtext)
ggplot(data.frame(x = c(-2, 2)), aes(x = x)) +
stat_function(fun = dnorm) +
geom_richtext(data = data.frame(x = c(-1.4, -.5), y = rep(dnorm(0, 2)), y1 = c('First', 'Second')),
aes(x = x, y = y, label = y1, fill = alpha(y1, 0.2))) +
scale_fill_manual(breaks = c('First', 'Second'), values = c('#c1121f', '#023e8a'), aesthetics = 'fill')
With this I am getting below error
Error: Unknown colour name: First
One option would be to use scales::alpha to set the alpha for the fill color:
library(ggplot2)
library(ggtext)
ggplot(df) +
aes(
x, y, label = label, angle = angle, color = color, fill = fill,
hjust = hjust, vjust = vjust
) +
geom_richtext(aes(fill = alpha(fill, 0.30))) +
geom_point(color = "black", size = 2) +
scale_color_identity() +
scale_fill_identity() +
xlim(0, 1) + ylim(0, 1)
EDIT For your second example we could or have to apply scales::alpha on the values of the fill scale. This however works only if we use the fill aes only in geom_richtext. If this is not the case than of course could we still apply one of both approaches side-by-side with the ggnewscale package.
library(ggplot2)
library(ggtext)
ggplot(data.frame(x = c(-2, 2)), aes(x = x)) +
stat_function(fun = dnorm) +
geom_richtext(
data = data.frame(x = c(-1.4, -.5), y = rep(dnorm(0, 2)), y1 = c("First", "Second")),
aes(x = x, y = y, label = y1, fill = y1)
) +
scale_fill_manual(
breaks = c("First", "Second"),
values = alpha(c("#c1121f", "#023e8a"), .2),
aesthetics = "fill"
)
Here is an alternative approach:
According to the documentation of ggtext
library(ggplot2)
library(ggtext)
ggplot(df) +
aes(
x, y, label = label, angle = angle, color = color,
hjust = hjust, vjust = vjust
) +
geom_richtext(
fill = NA, label.color = df$color, # remove background and outline
label.padding = grid::unit(rep(5, 10), "pt") # remove padding
) +
geom_point(color = "black", size = 2) +
scale_color_identity() +
xlim(0, 1) + ylim(0, 1)

ggplot geom_rect color gradient (without reference to data)?

I was wondering if it is possible to have a geom_rect with a color gradient without a data reference, i.e. outside of aes().
I would like the two rectangles in the bottom of the following plot to show a color gradient from red to white (left to right) and the top one to show a color gradient from yellow to white.
Is this possible in a simple way or do I have to create data to refer to?
ggplot() +
geom_rect(aes(xmin = c(1, 3), xmax = c(2.5, 4), ymin = c(1, 1), ymax = c(2, 2)), color = "black", fill = "red") +
geom_rect(aes(xmin = 1, xmax = 3.5, ymin = 3, ymax = 4), color = "black", fill = "yellow") +
theme_bw() +
theme(panel.grid = element_blank())
I tried to use scale_fill_gradient with geom_tile but this doesn't really do what I want: 1. the two supposed-to-be-red rectangles share a gradient and don't start with pure red each and 2. I can't manage to use two different scale_fill_gradient's in one plot.
foo <- tibble(x = seq(from = 1, to = 2.5, by = 0.001),
y = rep(1, 1501))
bar <- tibble(x = seq(from = 3, to = 4, by = 0.001),
y = rep(1, 1001))
foobar <- tibble(x = seq(from = 1, to = 3.5, by = 0.001),
y = rep(3, 2501))
ggplot() +
geom_tile(data = foo, aes(x = x, y = y, fill = x)) +
geom_tile(data = bar, aes(x = x, y = y, fill = x)) +
scale_fill_gradient(low = 'red', high = 'white') +
geom_tile(data = foobar, aes(x = x, y = y, fill = x)) +
scale_fill_gradient(low = 'yellow', high = 'white') +
theme_bw() +
theme(panel.grid = element_blank())
You could use the function new_scale_fill from ggnewscale between your two different scale_fill_gradient functions in your plot process. This will reset your aesthetics to make it possible to use another gradient like this:
library(tibble)
foo <- tibble(x = seq(from = 1, to = 2.5, by = 0.001),
y = rep(1, 1501))
bar <- tibble(x = seq(from = 3, to = 4, by = 0.001),
y = rep(1, 1001))
foobar <- tibble(x = seq(from = 1, to = 3.5, by = 0.001),
y = rep(3, 2501))
library(ggplot2)
library(ggnewscale)
ggplot() +
geom_tile(data = foo, aes(x = x, y = y, fill = x)) +
geom_tile(data = bar, aes(x = x, y = y, fill = x)) +
scale_fill_gradient(low = 'red', high = 'white') +
new_scale_fill() +
geom_tile(data = foobar, aes(x = x, y = y, fill = x)) +
scale_fill_gradient(low = 'yellow', high = 'white') +
theme_bw() +
theme(panel.grid = element_blank())
Created on 2022-09-23 with reprex v2.0.2
To add for each geom_tile a gradient color, you could use for each tile new_scale_fill like this:
library(ggplot2)
library(ggnewscale)
ggplot() +
geom_tile(data = foo, aes(x = x, y = y, fill = x)) +
scale_fill_gradient(low = 'red', high = 'white', guide = 'none') +
new_scale_fill() +
geom_tile(data = bar, aes(x = x, y = y, fill = x)) +
scale_fill_gradient(low = 'red', high = 'white') +
new_scale_fill() +
geom_tile(data = foobar, aes(x = x, y = y, fill = x)) +
scale_fill_gradient(low = 'yellow', high = 'white') +
theme_bw() +
theme(panel.grid = element_blank())
Created on 2022-09-23 with reprex v2.0.2

Polygon disappears when Plotly labels are defined - R

I am trying to plot a polygon hull using ggplot and plotly.
While without label polygons are shown in the plot, when I add extra labels in aesthetics the polygons disappear.
library(data.table)
library(ggplot2)
library(dplyr)
library(plotly)
df <- data.table(continent = c(rep("America",3), rep("Europe",4)),
state = c("USA", "Brasil", "Chile", "Italy", "Swiss", "Spain", "Greece"),
X = rnorm(7, 5, 1),
Y = rnorm(7, -13, 1)
)
df$X_sd = sd(df$X)
df$Y_sd = sd(df$Y)
hull2 <- df %>%
group_by(continent) %>%
slice(chull(X,Y))
p <- df %>%
ggplot( aes(x=X,
y=Y,
fill = continent,
color = continent,
label=state))+
geom_polygon(data = hull2,
lwd = 1,
alpha = 0.1,
linetype = "dashed")+
geom_errorbarh(aes(xmin = X - X_sd,
xmax = X + X_sd),
size = 0.5,
alpha = 0.3) +
geom_errorbar(aes(ymin = Y - Y_sd,
ymax = Y + Y_sd),
size = 0.5,
alpha = 0.3) +
geom_point(shape=21,
color="black",
size=3)+
theme_bw()+
theme(legend.position = "none")
ggplotly(p)
How odd! If you most label = state to the aes for the last geom_ you'll get the standard warning, but it works and the state shows up in the tooltip.
The designation of color = continent shows up, as well. I am going to guess that you're not interested in having that in your tooltip, so I've added how you could change that at the end. There is a tooltip with the continent listed two times, but with the information about how to remove the color, you'll see how you might make further adjustments depending on the trace.
p <- df %>%
ggplot(aes(x = X, y = Y,
fill = continent,
color = continent #,
# label = state)
)) +
geom_polygon(data = hull2, lwd = 1,
alpha = 0.1, linetype = "dashed") +
geom_errorbarh(aes(xmin = X - X_sd,
xmax = X + X_sd),
size = 0.5, alpha = 0.3) +
geom_errorbar(aes(ymin = Y - Y_sd,
ymax = Y + Y_sd),
size = 0.5, alpha = 0.3) +
geom_point(shape = 21,
color = "black",
size = 3, aes(label = state)) +
theme_bw() + theme(legend.position = "none")
p
ggplotly(p)
To remove the color from the tooltip, assign ggplotly to an object. Then you can remove the string from the 7th and 8th trace.
p1 = ggplotly(p)
lapply(7:8,
function(i){
p1$x$data[[i]]$text <<- stringr::str_replace(p1$x$data[[i]]$text,
"continent: black<br />",
"")
})
p1
FYI, there are 8 traces that make up your plot. The first trace has the double continent text.

Increase the margin of every second x-axis tick ggplot2

I'm looking for a way to move every second x-axis tick downwards and have the tick line go down with it.
I can change the general margin and tick length for all ticks with:
#MWE
library(ggplot2)
ggplot(cars, aes(dist, speed))+
geom_point()+
theme(
axis.ticks.length.x = unit(15, "pt")
)
But, I would like the x-axis ticks 0, 50, and 100 (i.e., every second tick) to be without the added top margin.
A generalized answer is preferred as my x-axis is categorical and not numerical (and contains 430 ticks, so nothing I can set by hand).
Any ideas?
Edit:
Output should be:
Edit2:
A more intricate example would be:
#MWE
ggplot(diamonds, aes(cut, price, fill = clarity, group = clarity))+
geom_col(position = 'dodge')+
theme(
axis.ticks.length.x = unit(15, "pt")
)
Edit -- added categorical approach at bottom.
Here's a hack. Hope there's a better way!
ticks <- data.frame(
x = 25*0:5,
y = rep(c(-0.2, -2), 3)
)
ggplot(cars, aes(dist, speed))+
geom_point()+
geom_rect(fill = "white", xmin = -Inf, xmax = Inf,
ymin = 0, ymax = -5) +
geom_segment(data = ticks,
aes(x = x, xend = x,
y = 0, yend = y)) +
geom_text(data = ticks,
aes(x = x, y = y, label = x), vjust = 1.5) +
theme(axis.ticks.x = element_blank()) +
scale_x_continuous(breaks = 25*0:5, labels = NULL, name = "") +
coord_cartesian(clip = "off")
Here's a similar approach used with a categorical x.
cats <- sort(as.character(unique(diamonds$cut)))
ticks <- data.frame(x = cats)
ticks$y = ifelse(seq_along(cats) %% 2, -500, -2000)
ggplot(diamonds, aes(cut, price, fill = clarity, group = clarity))+
geom_col(position = 'dodge') +
annotate("rect", fill = "white",
xmin = 0.4, xmax = length(cats) + 0.6,
ymin = 0, ymax = -3000) +
geom_segment(data = ticks, inherit.aes = F,
aes(x = x, xend = x,
y = 0, yend = y)) +
geom_text(data = ticks, inherit.aes = F,
aes(x = x, y = y, label = x), vjust = 1.5) +
scale_x_discrete(labels = NULL, name = "cut") +
scale_y_continuous(expand = expand_scale(mult = c(0, 0.05))) +
theme(axis.ticks.x = element_blank()) +
coord_cartesian(clip = "off")

How to customize a boxplot legend indicating mean, outliers, median, etc?

I have a boxplot and by my supervisor's advice I have to indicate the mean, outliers and median in the legend, like this image:
How can I do this using ggplot2?
library(ggplot2)
A <- 1:20
DF <- data.frame(A)
ggplot(data = DF) +
geom_boxplot(aes(x = "", y = A))
There is no straightforward way. But you could make a custom legend using another plot:
p <- ggplot(mtcars) +
geom_boxplot(aes(x = factor(cyl), y = mpg))
d1 <- data.frame(x = 1, y = c(1:1000, 1502))
d2 <- data.frame(
y = c(boxplot.stats(d1$y)$stats, 1502),
x = 1,
label = c('min', '1st quartile', 'median', '3rd quartile', 'max', 'outlier')
)
leg <- ggplot(d1, aes(x, y)) + geom_boxplot(width = 0.2) +
geom_text(aes(x = 1.15, label = label), d2, hjust = 0) +
xlim(0.9, 1.5) +
theme_void() + theme(panel.background = element_rect(fill = 'white', color = 1))
p + annotation_custom(ggplotGrob(leg), xmin = 3, xmax = 3.5, ymin = 25, ymax = 35)

Resources