In ggplot2, how can I change the border of selected facets? - r

Taking the graph from ggplot2 help pages:
ggplot(mtcars, aes(factor(cyl))) + geom_bar() + facet_grid(. ~ vs)
Is it possible to change the border (colour and/or thickness) of only selected panels? I'd like to, for instance, change the border of the facet of '1' of faceting variable vs.
I tried adding
theme(panel.border = element_rect(size = 3, colour = "red", fill = NA))
but that solution changes all borders.
I was also thinking about using geom_rect or geom_polygon but am not sure how to limit it to one plot either.
I stumbled upon this thread on R help list, but the solutions didn't work for me
Any suggestions on how to move forward will be much appreciated.

How about filling it with a colour like this?
dd <- data.frame(vs = c(0,1), ff = factor(0:1))
ggplot() + geom_rect(data=dd, aes(fill=ff),
xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf, alpha=0.15) +
geom_bar(data = mtcars, aes(factor(cyl))) + facet_grid(. ~ vs) +
scale_fill_manual(values=c(NA, "red"), breaks=NULL)

I was trying to implement a facet border as well. I did just a little tweaking of the answer supplied by Hadley in the thread mentioned in the question as follows:
# Outline colours
outline <- data.frame(
cyl = c(4, 6, 8),
outline_color = c('green', 'orange', 'red')
)
# Points defining square region for background
square <- with(mtcars, data.frame(
x = c(-Inf, Inf, Inf, -Inf),
y = c(-Inf, -Inf, Inf, Inf)
))
ggplot(mtcars, aes(x = mpg, y = wt)) +
geom_polygon(aes(x = x,y = y, color = outline_color, fill = NA), data = merge(outline, square)) +
geom_point() +
scale_fill_identity() +
facet_grid(. ~ cyl)
Produces the following graph with differing facet borders:

Related

Add label between colorbar breaks in ggplot2

I am trying to create a figure with ggplot and would like to add category names between colorbar breaks (values). I am using a graduated colorbar using the scale_color_fermenter function, which I think makes it a bit tricky to do this.
Below is an example code
library('ggplot2')
ggplot(mtcars, aes(x=mpg, y=carb, color=disp)) +
geom_point(size=3)+
scale_color_fermenter(breaks = c(100,300,400), palette = "Blues") #graduate colorbar
The resulting figure looks like this
I want to add categories (A, B, C, etc.) between the colorbar breaks (i.e., create categories for disp), such that
0<=A<100
100<=B<300
300<=C<400
400<=D<500
The resulting figure looks like this (or similar)
I know I can add extra breaks and change the label. Something like the following
scale_color_fermenter(breaks=c(50,100,200,300,350,400,450,500),
labels=c('A','100','B','300','C','400','D','500'))
But this would mess up the colorbar class (i.e., colorbar will have more colors), which is something I do not want.
Basically the same approach as by #zephryl but with some additional styling and fiddling and using ggtext::element_markdown just in case you want some additional styling for the text labels.
Using lineheight I add some padding between the tick and the category labels.
Using vjust I shift the labels so that the position of the tick labels corresponds approximately to the boundaries of the legend keys.
library("ggplot2")
mylabels <- function(x) {
paste0(
c(rep("", length(x) - 1), paste0("<span style='color: red'>", LETTERS[length(x) + 1], "</span><br>")),
x,
"<br><span style='color: red'>", LETTERS[seq_along(x)], "</span>"
)
}
ggplot(mtcars, aes(x = mpg, y = carb, color = disp)) +
geom_point(size = 3) +
scale_color_fermenter(breaks = c(100, 300, 400), labels = mylabels, palette = "Blues") +
theme(legend.text = ggtext::element_markdown(vjust = c(.85, .85, .55), lineheight = 1.25))
How about:
library(ggplot2)
ggplot(mtcars, aes(x = mpg, y = carb, color = disp)) +
geom_point(size = 3)+
scale_color_fermenter(
breaks = c(100,300,400),
labels = c("B\n100\nA", "C\n300\n", "D\n400\n"),
palette = "Blues"
)
Created on 2022-10-27 with reprex v2.0.2
An alternative is to draw the letters on as annotations:
ggplot(mtcars, aes(mpg, carb, color = disp)) +
geom_point(size = 3) +
scale_color_fermenter(breaks = c(100, 300, 400)) +
coord_cartesian(clip = "off") +
annotation_custom(grid::textGrob(c("A", "B", "C", "D"),
x = 1.02, y = seq(0.39, 0.57, 0.058))) +
theme(legend.box.margin = margin(10, 10, 10, 10))

Underline effect for graph and text using ggplot2

Do you know how to add the yellow highlight effect of this 538 graph for both text and graphs using ggplot2?
Thanks in advance!
Update after clarification
It really depends on the structure of the data and what you are using to plot. However, if you wanted to add large highlights to particular plots, then you could plot the same geom_line but change the aesthetics of it (though the highlight will not connect to adjacent plots).
library(ggplot2)
hlines <- mtcars %>%
group_by(cyl) %>%
summarise(MN = min(wt))
ggplot(mtcars) +
geom_line(aes(mpg, wt), colour = "lightyellow", size = 80) +
geom_line(aes(mpg, wt)) +
geom_hline(
data = hlines,
aes(yintercept = MN),
linetype = "dotted",
color = "grey",
size = 1.5
) +
facet_wrap( ~ cyl) +
theme_bw()
Output
For text, in ggplot2, you can add fill to the background of annotations. But it again really depends on the structure and how you are plotting the text. You could split up the annotations, so that you could fill one and not the other part of the text.
ggplot(mtcars) +
geom_line(aes(mpg, wt), colour = "lightyellow", size = 80) +
geom_line(aes(mpg, wt)) +
annotate(
geom = "text",
x = 30,
y = 5,
label = "It hasn't really dropped off"
) +
annotate(
geom = "label",
x = 30,
y = 4.75,
label = "since he first won office in 2016",
fill = "lightyellow",
label.size = NA
)
Output
First Answer
It depends on what exactly you are looking for/what your data looks like. But if you are wanting to place a line at the minimum under a line graph in a faceted plot, then you could do something like this:
library(ggplot2)
hlines <- mtcars %>%
group_by(cyl) %>%
summarise(MN = min(wt))
ggplot(mtcars) +
geom_line(aes(mpg, wt)) +
geom_hline(
data = hlines,
aes(yintercept = MN),
linetype = "dotted",
color = "grey",
size = 1.5
) +
facet_wrap( ~ cyl) +
theme_bw()
Output
If you just have a single plot, then you can use geom_hline and just provide the y intercept.
ggplot(mtcars) +
geom_line(aes(mpg, wt)) +
geom_hline(yintercept = 3.5,
linetype = "dotted",
color = "grey",
size = 1.5
) +
theme_bw()

How to avoid over lapping bubbles in bubble plot?

I want to separately plot data in a bubble plot like the image right (I make this in PowerPoint just to visualize).
At the moment I can only create a plot that looks like in the left where the bubble are overlapping. How can I do this in R?
b <- ggplot(df, aes(x = Year, y = Type))
b + geom_point(aes(color = Spp, size = value), alpha = 0.6) +
scale_color_manual(values = c("#0000FF", "#DAA520", "#228B22","#E7B888")) +
scale_size(range = c(0.5, 12))
You can have the use of position_dodge() argument in your geom_point. If you apply it directly on your code, it will position points in an horizontal manner, so the idea is to switch your x and y variables and use coord_flip to get it in the right way:
library(ggplot2)
ggplot(df, aes(y = as.factor(Year), x = Type))+
geom_point(aes(color = Group, size = Value), alpha = 0.6, position = position_dodge(0.9)) +
scale_color_manual(values = c("#0000FF", "#DAA520", "#228B22","#E7B888")) +
scale_size(range = c(1, 15)) +
coord_flip()
Does it look what you are trying to achieve ?
EDIT: Adding text in the middle of each points
To add labeling into each point, you can use geom_text and set the same position_dodge2 argument than for geom_point.
NB: I use position_dodge2 instead of position_dodge and slightly change values of width because I found position_dodge2 more adapted to this case.
library(ggplot2)
ggplot(df, aes(y = as.factor(Year), x = Type))+
geom_point(aes(color = Group, size = Value), alpha = 0.6,
position = position_dodge2(width = 1)) +
scale_color_manual(values = c("#0000FF", "#DAA520", "#228B22","#E7B888")) +
scale_size(range = c(3, 15)) +
coord_flip()+
geom_text(aes(label = Value, group = Group),
position = position_dodge2(width = 1))
Reproducible example
As you did not provide a reproducible example, I made one that is maybe not fully representative of your original dataset. If my answer is not working for you, you should consider providing a reproducible example (see here: How to make a great R reproducible example)
Group <- c(LETTERS[1:3],"A",LETTERS[1:2],LETTERS[1:3])
Year <- c(rep(1918,4),rep(2018,5))
Type <- c(rep("PP",3),"QQ","PP","PP","QQ","QQ","QQ")
Value <- sample(1:50,9)
df <- data.frame(Group, Year, Value, Type)
df$Type <- factor(df$Type, levels = c("PP","QQ"))

ggplot outline jitter datapoints

I'm trying to create a scatterplot where the points are jittered (geom_jitter), but I also want to create a black outline around each point. Currently I'm doing it by adding 2 geom_jitters, one for the fill and one for the outline:
beta <- paste("beta == ", "0.15")
ggplot(aes(x=xVar, y = yVar), data = data) +
geom_jitter(size=3, alpha=0.6, colour=my.cols[2]) +
theme_bw() +
geom_abline(intercept = 0.0, slope = 0.145950, size=1) +
geom_vline(xintercept = 0, linetype = "dashed") +
annotate("text", x = 2.5, y = 0.2, label=beta, parse=TRUE, size=5)+
xlim(-1.5,4) +
ylim(-2,2)+
geom_jitter(shape = 1,size = 3,colour = "black")
However, that results in something like this:
Because jitter randomly offsets the data, the 2 geom_jitters are not in line with each other. How do I ensure the outlines are in the same place as the fill points?
I've see threads about this (e.g. Is it possible to jitter two ggplot geoms in the same way?), but they're pretty old and not sure if anything new has been added to ggplot that would solve this issue
The code above works if, instead of using geom_jitter, I use the regular geom_point, but I have too many overlapping points for that to be useful
EDIT:
The solution in the posted answer works. However, it doesn't quite cooperate for some of my other graphs where I'm binning by some other variable and using that to plot different colours:
ggplot(aes(x=xVar, y = yVar, color=group), data = data) +
geom_jitter(size=3, alpha=0.6, shape=21, fill="skyblue") +
theme_bw() +
geom_vline(xintercept = 0, linetype = "dashed") +
scale_colour_brewer(name = "Title", direction = -1, palette = "Set1") +
xlim(-1.5,4) +
ylim(-2,2)
My group variable has 3 levels, and I want to colour each group level by a different colour in the brewer Set1 palette. The current solution just colours everything skyblue. What should I fill by to ensure I'm using the correct colour palette?
You don't actually have to use two layers; you can just use the fill aesthetic of a plotting character with a hole in it:
# some random data
set.seed(47)
df <- data.frame(x = rnorm(100), y = runif(100))
ggplot(aes(x = x, y = y), data = df) + geom_jitter(shape = 21, fill = 'skyblue')
The colour, size, and stroke aesthetics let you customize the exact look.
Edit:
For grouped data, set the fill aesthetic to the grouping variable, and use scale_fill_* functions to set color scales:
# more random data
set.seed(47)
df <- data.frame(x = runif(100), y = rnorm(100), group = sample(letters[1:3], 100, replace = TRUE))
ggplot(aes(x=x, y = y, fill=group), data = df) +
geom_jitter(size=3, alpha=0.6, shape=21) +
theme_bw() +
geom_vline(xintercept = 0, linetype = "dashed") +
scale_fill_brewer(name = "Title", direction = -1, palette = "Set1")

Make the background of a graph different colours in different regions

I'm making a straightforward barchart in R using the ggplot2 package. Rather than the grey default I'd like to divide the background into five regions, each a different (but similarly understated) colour. How do I do this?
More specifically, I'd like the five coloured regions to run from 0-25, 25-45, 45-65, 65-85 and 85-100 where the colours represent worse-than-bronze, bronze, silver, gold and platinum respectively. Suggestions for a colour scheme very welcome too.
Here's an example to get you started:
#Fake data
dat <- data.frame(x = 1:100, y = cumsum(rnorm(100)))
#Breaks for background rectangles
rects <- data.frame(xstart = seq(0,80,20), xend = seq(20,100,20), col = letters[1:5])
#As Baptiste points out, the order of the geom's matters, so putting your data as last will
#make sure that it is plotted "on top" of the background rectangles. Updated code, but
#did not update the JPEG...I think you'll get the point.
ggplot() +
geom_rect(data = rects, aes(xmin = xstart, xmax = xend, ymin = -Inf, ymax = Inf, fill = col), alpha = 0.4) +
geom_line(data = dat, aes(x,y))
I wanted to move the line⎯or the bars of the histogram⎯to the foreground, as suggested by baptiste above and fix the background with
+ theme(panel.background = element_rect(), panel.grid.major = element_line( colour = "white") ), unfortunately I could only do it by sending the geom_bar twice, hopefully someone can improve the code and make the answer complete.
background <- data.frame(lower = seq( 0 , 3 , 1.5 ),
upper = seq( 1.5, 4.5, 1.5 ),
col = letters[1:3])
ggplot() +
geom_bar( data = mtcars , aes( factor(cyl) ) ) +
geom_rect( data = background ,
mapping = aes( xmin = lower ,
xmax = upper ,
ymin = 0 ,
ymax = 14 ,
fill = col ) ,
alpha = .5 ) +
geom_bar(data = mtcars,
aes(factor(cyl))) +
theme(panel.background = element_rect(),
panel.grid.major = element_line( colour = "white"))
Produces this,
Take a look at this site for colour scheme suggestions.
Since you are after vertical (or horizontal) area highlighting, geom_rect() might be an overshoot. Consider geom_ribbon() instead:
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
geom_ribbon(aes(xmin=3, xmax=4.2), alpha=0.25) +
theme_minimal()

Resources