annotate ggplot above plot - r

I tried lately to annotate a graph with boxes above a ggplot.
Here is what I want:
I found a way using grid, but I find it too complicated, and I am quite sure there is a better way to do it, more ggplot2 friendly. Here is the example and my solution:
the data:
y2 <- 350
mesure_pol <- data.frame(x1 = c(1,4,7),
x2 = c(4,7,10),
politiquecat = c(1:3),
politique = c("Phase 1\n","Phase 2\n","Phase 3\n"),
y = c(y2,y2,y2)
)
mesure_pol$x_median <- (mesure_pol$x1 + mesure_pol$x2)/2
colorpal <- viridis::inferno(n=3,direction = -1)
plot
the main plot
p <- ggplot(data = mesure_pol) +
geom_rect(aes(xmin = x1,
xmax = x2,
ymin = 0,
ymax = 300,
fill = as.factor(politiquecat)),
fill = colorpal,
color = "black",
size = 0.3,
alpha = 0.2)+
theme(plot.margin=unit(c(60, 5.5, 5.5, 5.5), "points"))+
coord_cartesian(clip = 'off')
the annotation part
Here is the part I am not happy with:
for (i in 1:dim(mesure_pol)[1]) {
text <- textGrob(label = mesure_pol[i,"politique"], gp = gpar(fontsize=7,fontface="bold"),hjust = 0.5)
rg <- rectGrob(x = text$x, y = text$y, width = stringWidth(text$label) - unit(3,"mm") ,
height = stringHeight(text$label) ,gp = gpar(fill=colorpal[i],alpha = 0.3))
p <- p + annotation_custom(
grob = rg,
ymin = mesure_pol[i,"y"], # Vertical position of the textGrob
ymax = mesure_pol[i,"y"],
xmin = mesure_pol[i,"x_median"], # Note: The grobs are positioned outside the plot area
xmax = mesure_pol[i,"x_median"]) +
annotation_custom(
grob = text,
ymin = mesure_pol[i,"y"], # Vertical position of the textGrob
ymax = mesure_pol[i,"y"],
xmin = mesure_pol[i,"x_median"], # Note: The grobs are positioned outside the plot area
xmax = mesure_pol[i,"x_median"])
}
Is there a simplier/nicer way to obtain similar result ? I tried with annotate, label but without any luck.

An alternative approach to achieve the desired result would be to make the annotations via a second ggplot which could be glued to the main plot via e.g. patchwork.
For the annotation plot I basically used your code for the main plot, added a geom_text layer, get rid of the axix, etc. via theme_void and set the limits in line with main plot. Main difference is that I restrict the y-axis to a 0 to 1 scale. Besides that I shifted the xmin, xmax, ymin and ymax values to add some space around the rectangels (therefore it is important to set the limits).
library(ggplot2)
library(patchwork)
y2 <- 350
mesure_pol <- data.frame(x1 = c(1,4,7),
x2 = c(4,7,10),
politiquecat = c(1:3),
politique = c("Phase 1\n","Phase 2\n","Phase 3\n"),
y = c(y2,y2,y2)
)
mesure_pol$x_median <- (mesure_pol$x1 + mesure_pol$x2)/2
colorpal <- viridis::inferno(n=3,direction = -1)
p <- ggplot(data = mesure_pol) +
geom_rect(aes(xmin = x1,
xmax = x2,
ymin = 0,
ymax = 300,
fill = as.factor(politiquecat)),
fill = colorpal,
color = "black",
size = 0.3,
alpha = 0.2)
ann <- ggplot(data = mesure_pol) +
geom_rect(aes(xmin = x1 + 1,
xmax = x2 - 1,
ymin = 0.2,
ymax = 0.8,
fill = as.factor(politiquecat)),
fill = colorpal,
color = "black",
size = 0.3,
alpha = 0.2) +
geom_text(aes(x = x_median, y = .5, label = politique), vjust = .8, fontface = "bold", color = "black") +
coord_cartesian(xlim = c(1, 10), ylim = c(0, 1)) +
theme_void()
ann / p +
plot_layout(heights = c(1, 4))

By setting a second x-axis and filling the background of the new axis labels with element_markdown from the ggtext package. You may achieve this:
Here is the code:
library(ggtext)
y2 <- 350
mesure_pol <- data.frame(x1 = c(1,4,7),
x2 = c(4,7,10),
politiquecat = c(1:3),
politique = c("Phase 1\n","Phase 2\n","Phase 3\n"),
y = c(y2,y2,y2)
)
mesure_pol$x_median <- (mesure_pol$x1 + mesure_pol$x2)/2
p <- ggplot(data = mesure_pol) +
geom_rect(aes(xmin = x1,
xmax = x2,
ymin = 0,
ymax = 300,
fill = as.factor(politiquecat)),
fill = c("yellow", "red", "black"),
color = "black",
size = 0.3,
alpha = 0.2) +
scale_x_continuous(sec.axis = dup_axis(name = "",
breaks = c(2.5, 5.5, 8.5),
labels = c("Phase 1", "Phase 2", "Phase 3"))) +
theme(plot.margin=unit(c(60, 5.5, 5.5, 5.5), "points"),
axis.ticks.x.top = element_blank(),
axis.text.x.top = element_markdown(face = "bold",
size = 12,
fill = adjustcolor(c("yellow", "red", "black"),
alpha.f = .2)))+
coord_cartesian(clip = 'off')

Related

R: How to set full transparency in a quantile line in geom_density_ridges

First of all, some data similar to what I am working with.
rawdata <- data.frame(Score = rnorm(1000, seq(1, 0, length.out = 10), sd = 1),
Group = rep(LETTERS[1:3], 10000))
rawdata$Score <- ifelse(rawdata$Group == "A", rawdata$Score+2,rawdata$Score)
rawdata$Score <- ifelse(rawdata$Group == "C", rawdata$Score-2,rawdata$Score)
stdev <- c(10.78,10.51,9.42)
col <- c("#004d8d", "#cc2701", "#e5b400")
Now, the code of my geom_density_ridges with quantile lines, which in this case they will be white.
p <- ggplot(rawdata, aes(x = Score, y = Group)) +
scale_y_discrete() +
geom_rect(inherit.aes = FALSE, mapping = aes(ymin = 0, ymax = Inf, xmin = -0.1 * min(stdev), xmax = 0.1 * max(stdev)),
fill = "grey", alpha = 0.5) +
geom_density_ridges(scale = -0.5, size = 1, alpha=0.5, show.legend = FALSE,
quantile_lines = TRUE, quantiles = c(0.025, 0.975),
vline_color = "white", aes(fill = Group)) +
scale_color_manual(values = col) +
scale_fill_manual(values = col) +
labs(title="Toy Graph", y="Group", x="Value") +
coord_flip(xlim = c(-8, 8), ylim = NULL, expand = TRUE, clip = "on")
p
An we obtain the following plot, which is perfectly adjusted to expectation.
Now I was wondering if there was a way to make only this little white quantile line transparent to the background. I tried first to set the vline_color = "transparent" and leaving the aes(fill = Group) at the end of geom_density_ridges at the logic that options where drew in order but it gets transparent not to the different shades of grey background but to the density fill (so the quantile line disappears), which is not what I am trying to achieve.
Thanks in advance for your ideas!
Colors can be modified with scales::alpha. This can be passed to your color argument.
library(ggridges)
library(ggplot2)
rawdata <- data.frame(Score = rnorm(1000, seq(1, 0, length.out = 10), sd = 1),
Group = rep(LETTERS[1:3], 10000))
rawdata$Score <- ifelse(rawdata$Group == "A", rawdata$Score+2,rawdata$Score)
rawdata$Score <- ifelse(rawdata$Group == "C", rawdata$Score-2,rawdata$Score)
stdev <- c(10.78,10.51,9.42)
col <- c("#004d8d", "#cc2701", "#e5b400")
ggplot(rawdata, aes(x = Score, y = Group)) +
scale_y_discrete() +
geom_rect(inherit.aes = FALSE, mapping = aes(ymin = 0, ymax = Inf, xmin = -0.1 * min(stdev), xmax = 0.1 * max(stdev)),
fill = "grey", alpha = 0.5) +
geom_density_ridges(scale = -0.5, size = 1, alpha=0.5, show.legend = FALSE,
quantile_lines = TRUE, quantiles = c(0.025, 0.975),
### The only change is here
vline_color = alpha("white", .5), aes(fill = Group)) +
scale_color_manual(values = col) +
scale_fill_manual(values = col) +
labs(title="Toy Graph", y="Group", x="Value") +
coord_flip(xlim = c(-8, 8), ylim = NULL, expand = TRUE, clip = "on")
#> Picking joint bandwidth of 0.148
#> Warning: Using the `size` aesthietic with geom_segment was deprecated in ggplot2 3.4.0.
#> ℹ Please use the `linewidth` aesthetic instead.
Created on 2022-11-14 with reprex v2.0.2
No, if you make something transparent you will see what's underneath, which is the density plot.
However, you can replicate the visual effect of "seeing through to the background" by simply setting the line colour to the same as the background.
Your grey rectangle is currently plotted underneath the density plots, therefore the "background" doesn't have a single colour. This can be solved by plotting it on top instead. Instead of a 50% grey with 50% alpha, you can replicate the same effect with a 0% grey (aka black) with a 25% alpha. Move the geom_rect later than the density plots and it will be layered on top.
Finally, your geom_rect is being called once for each row of raw_data, since it inherits the same data as the main plot. You probably don't want that, so specify a (dummy) data source instead.
ggplot(rawdata, aes(x = Score, y = Group)) +
scale_y_discrete() +
geom_density_ridges(scale = -0.5, size = 1, alpha=0.5, show.legend = FALSE,
quantile_lines = TRUE, quantiles = c(0.025, 0.975),
vline_color = "grey90", aes(fill = Group)) +
scale_color_manual(values = col) +
scale_fill_manual(values = col) +
labs(title="Toy Graph", y="Group", x="Value") +
geom_rect(data=data.frame(), inherit.aes = FALSE, mapping = aes(
ymin = 0, ymax = Inf, xmin = -0.1 * min(stdev), xmax = 0.1 * max(stdev)
), fill = "black", alpha = 0.25) +
coord_flip(xlim = c(-8, 8), ylim = NULL, expand = TRUE, clip = "on")
Note: I'm not sure the background colour is really "grey90", I've eyeballed it. You may want to specify it explicitly with theme if you want to be exact.
If you want literal see-through portions of your density curves, you will need to make the gaps yourself:
library(tidyverse)
rawdata %>%
mutate(GroupNum = as.numeric(as.factor(Group))) %>%
group_by(GroupNum, Group) %>%
summarise(yval = first(GroupNum) - density(Score)$y,
xval = density(Score)$x,
q025 = quantile(Score, 0.025),
q975 = quantile(Score, 0.975)) %>%
mutate(Q = ifelse(xval < q025, 'low', ifelse(xval > q975, 'hi', 'mid'))) %>%
ggplot(aes(xval, yval, group = interaction(Group, Q))) +
geom_line(size = 1) +
geom_ribbon(aes(ymax = GroupNum, ymin = yval, fill = Group),
color = NA, alpha = 0.5, outline.type = 'full',
data = . %>% filter(abs(q025 - xval) > 0.03 &
abs(q975 - xval) > 0.03)) +
coord_flip() +
scale_fill_manual(values = col) +
scale_y_continuous(breaks = 1:3, labels = levels(factor(rawdata$Group)),
name = 'Group') +
labs(x = 'Score')

How to remove border from quadrant lines in geom_point plot (ggplot2) after adding "size"

How to remove border from quadrant lines in geom_point plot (ggplot2) after adding "size"?
ggplot(
DurablesSIZE,
aes(
x = DurablesSIZE$`GDP LQ`,
y = DurablesSIZE$Slope,
color = DurablesSIZE$Sector,
size = DurablesSIZE$`2019 GDP`
)
) +
geom_point() +
geom_hline(yintercept = 0) +
geom_vline(xintercept = 1) +
xlim(0, 5.5) +
ylim(-0.26, 0.26) +
geom_rect(aes(
xmin = 1,
xmax = Inf,
ymin = 0,
ymax = Inf
),
fill = "green",
alpha = 0.03) +
geom_rect(aes(
xmin = -Inf,
xmax = 1,
ymin = -Inf,
ymax = 0
),
fill = "red",
alpha = 0.03) +
geom_rect(aes(
xmin = -Inf,
xmax = 1,
ymin = 0,
ymax = Inf
),
fill = "yellow",
alpha = 0.03) +
geom_rect(aes(
xmin = 1,
xmax = Inf,
ymin = -Inf,
ymax = 0
),
fill = "yellow",
alpha = 0.03) +
labs(y = "Slope of GDP LQ (5Y)",
x = "2019 GDP LQ",
color = "Sector",
size = "2019 GDP") +
ggtitle("Oregon Durable Manufacturing \nTargeting Potential (GDP)") +
geom_text(
aes(label = ifelse(Slope > 0 & LQ > 1, as.character(Sector), '')),
hjust = 0,
vjust = 0,
size = 2.5,
nudge_x = -0.07,
nudge_y = 0.013
) +
theme(legend.key = element_rect(colour = NA, fill = NA),
legend.box.background = element_blank())
After adding size to my points, there is a weird border around the quadrant line weird border.
The size aesthetic is being applied globally, so it is creating a thick border around each geom_rect -- it controls border width for that geom.
To remove it, take size out of the global aes mapping and use geom_point(aes(size = '2019 GDP')) + to apply it to that layer alone.
Another note: if you use geom_rect for annotation purposes, it will be plotted once for each relevant line of your data, leading to massive overplotting and minimal control of alpha. It will be better to use annotate("rect" ...) for those, or to create a separate summary table which those layers can refer to so they only plot once.
Here's some fake data I made up so that I could run your code. Please include something like this in your questions.
DurablesSIZE <- tibble(
`GDP LQ` = 0.5*(1:10),
LQ = 10:1,
Slope = 0.05*(-4:5),
Sector = rep(LETTERS[1:5], 2),
`2019 GDP` = 1:10
)
Result with original code:
Revision with size aesthetic only applied locally:

Arrange Microscopic images in table for publication

I wonder if there is an automated way to align several microscopic images together in R to appear in such form like this image (source: doi: https://doi.org/10.1101/2019.12.11.873471). I am not looking for image analysis, only grid the images and add labels. I tried with magick in which I was able to write labels on the images and with gridExtra to align them and add the labels outside. but still not satisfied because I wasn't able to control the distance between the blocks and add labels in boxes like the image above.
can anybody recommend a package to do something like this ( maybe in R or Python, not sure if Latex can do something like that also?).
below is my reproducible code and what I get.
Many thanks for your help.
library(magick)
library(grid)
library(gridExtra)
names_of_images <- LETTERS[1:16]
pic_url <- "https://imagehost.imageupload.net/2020/04/30/EXAMPLE.jpg"
pic_cat <- tempfile()
download.file(pic_url,pic_cat,mode="wb")
pic <- image_read(pic_cat)
## write labels on images
image_listall <- list()
for ( i in names_of_images ) {
im_read_bor <- image_border(pic , 'white' ,geometry = "10x10")
im_read_bor_anno <- image_annotate(im_read_bor, paste(i),
size = 100, color = "white" , location = "+50+40" )
image_listall[[i]] = im_read_bor_anno
}
## arrange images in rows
row1 <- image_append(c(image_listall$A, image_listall$B ,image_listall$C,image_listall$D ), stack = F)
row2 <- image_append(c(image_listall$E, image_listall$F ,image_listall$G,image_listall$H ), stack = F)
row3 <- image_append(c(image_listall$I, image_listall$J,image_listall$K,image_listall$L) ,stack = F)
row4 <- image_append(c(image_listall$M, image_listall$N,image_listall$O, image_listall$P) ,stack = F)
## now add row labels and title
r1 <- grid.arrange(rasterGrob(row1) , top = textGrob(
"First Block",just = "center",
gp = gpar(fontface = 'bold', fontsize = 18)) ,
left = textGrob(
"(A)",
gp = gpar(fontface = 'bold', fontsize = 15)))
r2 <- grid.arrange(rasterGrob(row2) ,
left = textGrob(
"(B)",
gp = gpar(fontface = 'bold', fontsize = 15)))
r3 <- grid.arrange(rasterGrob(row3) , top = textGrob(
"Second Block", just = "center",
gp = gpar(fontface = 'bold', fontsize = 18)) ,
left = textGrob(
"(C)",
gp = gpar(fontface = 'bold', fontsize = 15)))
r4 <- grid.arrange(rasterGrob(row4) ,
left = textGrob(
"(D)",
gp = gpar(fontface = 'bold', fontsize = 15)))
## draw all together
grid.draw(rbind(r1, r2,r3,r4, size = "last"))
it looks like this:
Maybe not the best and more elegant solution, but a possible way will be to use the function facet_grid from ggplot2 to draw multipanel plot. The advantage of using ggplot2 will be that you can benefit for a large panel of tools pretty easy to use to customize the location, the font, the color of all your labels.
So, you can prepare a fake dataframe with your text for each vertical and horizontal label:
verticallabel <- c("Control", "cKO")
horizontallabel <- c("Text1","Text2","Text3")
text <- expand.grid(verticallabel,horizontallabel)
text <- as.data.frame(text)
Var1 Var2
1 Control Text1
2 cKO Text1
3 Control Text2
4 cKO Text2
5 Control Text3
6 cKO Text3
Then, you can create an empty plot with 6 panels with both horizontal and vertical labeling as follow:
library(ggplot2)
g <- ggplot(text, aes(x = Var1, y = Var2))+geom_point(color = NA)+
facet_grid(Var1~Var2, switch = "y")+ labs(tag = "A")+
theme(strip.background = element_blank(),
strip.text = element_blank(),
axis.text = element_blank(),
axis.title = element_blank(),
panel.background = element_blank(),
axis.ticks = element_blank(),
plot.margin = margin(1,1,1,1, unit = "cm"),
plot.tag.position = c(-0.015, 1.05))+
coord_cartesian(clip = "off", ylim = c(0,5), xlim = c(0,2))+
geom_text(data = subset(text, Var1 == "Control"), aes(label = Var2, x = 1, y = 6.3, color = Var2), show.legend = FALSE,vjust = 0.5)+
geom_text(data = subset(text, Var2 == "Text1"), aes(label = Var1, x = -0.8, y = 2.5, angle = 90, vjust = 0))+
geom_rect(data = subset(text, Var1 == "Control"), aes(xmin = -Inf, xmax = Inf, ymax = 6.8, ymin = 5.8), fill = NA, color = "black")+
geom_rect(data = subset(text, Var2 == "Text1"), aes(ymin = -Inf, ymax = Inf, xmin = -1, xmax = -0.7), fill = NA, color = "black")
Then, if you want to add image on each panel, you can use the excellent solution proposed by #EdgarSantos in this post: Adding custom images to ggplot facets
annotation_custom2 <-
function (grob, xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf, data){ layer(data = data, stat = StatIdentity, position = PositionIdentity,
geom = ggplot2:::GeomCustomAnn,
inherit.aes = TRUE, params = list(grob = grob,
xmin = xmin, xmax = xmax,
ymin = ymin, ymax = ymax))}
And here with some example images (some are downloaded on my computer, so you need to adapt path for your images):
library(png)
img1 = readPNG(getURLContent('https://cdn2.iconfinder.com/data/icons/animals/48/Turtle.png'))
img2 = readPNG(getURLContent('https://cdn2.iconfinder.com/data/icons/animals/48/Elephant.png'))
img3 = readPNG(getURLContent('https://cdn2.iconfinder.com/data/icons/animals/48/Hippopotamus.png'))
rlogo <- readPNG("../external-content.duckduckgo.com.png")
rstudio <- readPNG("../rstudio.png")
g +
annotation_custom2(rasterGrob(img1, width =unit(1,"npc"), height = unit(1,"npc")),
xmin = -Inf, xmax =Inf, ymin = -Inf, ymax = Inf, data = text[1,])+
annotation_custom2(rasterGrob(img2, width =unit(1,"npc"), height = unit(1,"npc")),
xmin = -Inf, xmax =Inf, ymin = -Inf, ymax = Inf, data = text[2,])+
annotation_custom2(rasterGrob(img3, width =unit(1,"npc"), height = unit(1,"npc")),
xmin = -Inf, xmax =Inf, ymin = -Inf, ymax = Inf, data = text[3,])+
annotation_custom2(rasterGrob(rlogo, width =unit(1,"npc"), height = unit(1,"npc")),
xmin = -Inf, xmax =Inf, ymin = -Inf, ymax = Inf, data = text[4,])+
annotation_custom2(rasterGrob(rstudio, width =unit(1,"npc"), height = unit(1,"npc")),
xmin = -Inf, xmax =Inf, ymin = -Inf, ymax = Inf, data = text[5,])
Does it answer your question ?

R ggplot background color boxplot

I have a dataframe like this one:
value = runif(n = 1000)
type = rep(c("a","b","c","d"),250)
type2 = rep(c("a","b"),500)
number = sample(1:4, 1000, replace=TRUE, prob=c(0.25, 0.25, 0.25, 0.25) )
feature = c(rep("small",500),rep("big",500))
allResults <- data.frame(value,type,type2,number,feature)
I'd like to color the background of boxplot by type2 value. If i use fill and col, it's not very clear. I think is more intutitive the background color if is possible.
library("ggplot2")
ggplot(allResults, aes(y=value, x=type)) + geom_boxplot(alpha=.3, aes(fill = type,col=type2)) +
ggtitle("comparison") + facet_grid(feature ~ number) +
theme(legend.position = "bottom",axis.text.x = element_text(angle = 90, hjust = 1)) +
scale_y_continuous(breaks = seq(0, 1, by = 0.05),limits = c(0,1))
This is my result at the moment:
I have seen that is possible to color the backgroud using geom_rect() but I don't understand how to apply.
You could use geom_rect and set your divisions. I originally had a and b as your rects factors, but to match colors in your type fill just set them to a and c.
value = runif(n = 1000)
type = rep(c("a","b","c","d"),250)
type2 = rep(c("a","b"),500)
number = sample(1:4, 1000, replace=TRUE, prob=c(0.25, 0.25, 0.25, 0.25) )
feature = c(rep("small",500),rep("big",500))
nFac <- 4 # define number of factors (types) here
rects <- data.frame(xmin = head(seq <- seq(0.5, nFac + .5, 1), -1),
xmax = tail(seq, -1), rect_type = c("a", "c")) #set your divisions here
allResults <- data.frame(value,type,type2,number,feature, rects)
ggplot(allResults, aes(y=value, x=type)) + geom_boxplot(aes(fill = type, col=type2)) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = -Inf, ymax = Inf, fill = rect_type), alpha = 0.009) +
ggtitle("comparison") + facet_grid(feature ~ number) +
theme(legend.position = "bottom",axis.text.x = element_text(angle = 90, hjust = 1)) +
scale_y_continuous(breaks = seq(0, 1, by = 0.05),limits = c(0,1))

Blend Colours from Different Layers

I'm trying to create a Venn diagram where each circle has a unique colour, and the intersections blend those colours.
I can make the circles with the ggforce package. And I can blend the colours by setting the alpha values to, say, 0.75:
library(ggplot2)
library(ggforce)
propositions <- data.frame(
cirx = c(-.75 , .75),
ciry = c(0 , 0),
r = c(1.5 , 1.5),
labx = c(-2.25 , 2.25),
laby = c(1 , 1),
labl = c("A", "B")
)
ggplot(propositions) +
theme_void() + coord_fixed() +
xlim(-3,3) + ylim(-2,2) +
theme(panel.border = element_rect(colour = "black", fill = NA, size = 1)) +
geom_circle(aes(x0 = cirx, y0 = ciry, r = r), fill = "red", alpha = .6, data = propositions[1,]) +
geom_circle(aes(x0 = cirx, y0 = ciry, r = r), fill = "blue", alpha = .6, data = propositions[2,]) +
geom_text(aes(x = labx, y = laby, label = labl),
fontface = "italic", size = 10, family = "serif")
But the results are pretty poor:
The colours are washed out, and the intersection's colour isn't as distinct from the right-side circle's as I'd like. I want something closer to this (photoshopped) result:
I could do this if there was some way to designate and fill the intersection. In principle, this could be done with geom_ribbon(), I think. But that seems painful, and hacky. So I'm hoping for a more elegant solution.
Here's the workaround using geom_ribbon(). It's not a proper solution though, since it won't generalize to other shapes and intersections without manually redefining the boundaries of the ribbon, which can get real hairy fast.
There's gotta be a way to get ggplot2 to automatically do the work of blending colours across layers, right?
library(ggplot2)
library(ggforce)
x <- seq(-.75, .75, 0.01)
upper <- function(x) {
a <- sqrt(1.5^2 - (x[x < 0] - .75)^2)
b <- sqrt(1.5^2 - (x[x >= 0] + .75)^2)
c(a,b)
}
lower <- function(x) {
-upper(x)
}
ggplot() +
coord_fixed() + theme_void() +
xlim(-3,3) + ylim(-2,2) +
geom_circle(aes(x0 = -.75, y0 = 0, r = 1.5), fill = "red") +
geom_circle(aes(x0 = .75, y0 = 0, r = 1.5), fill = "blue") +
geom_ribbon(aes(x = x, ymin = upper(x), ymax = lower(x)), fill = "purple", colour = "black") +
theme(panel.border = element_rect(colour = "black", fill = NA, size = 1)) +
geom_text(aes(x = c(-2.25, 2.25), y = c(1, 1), label = c("A", "B")),
fontface = "italic", size = 10, family = "serif")

Resources