annotation_custom size in ggplot2 - r

Hello I used this code in order to get a ggplot figure :
ggplot(mod_mat_constraint, aes(x=Categorie, y=label)) + scale_fill_manual(values = c("#86d65e","#404040","#86d65e","#40c5e8","#e84a4a","#86d65e","#404040","#e2e2e2"), breaks=label_text) +
theme_tree2() + geom_tile(aes(fill = Value), colour = "black") + facet_wrap(~ facet) +
scale_y_discrete(limits=rev(list_tax_order))+
coord_cartesian(clip='off') +
annotation_custom(valigned,xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf)+
theme(legend.position="none",plot.margin = unit(c(0, 12, 0, 0), "cm"))
so it just display a heatmap with a table next to it.
In order to add the the table I use then : annotation_custom(valigned,xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf)
so I can move the table everywhere I want but I do not know how I can deal with the size of the df ?
I previously create the table with :
g1<-tableGrob(Resricted_df_heatmap3[1],rows = NULL)
g2<-tableGrob(Resricted_df_heatmap3[2],rows = NULL)
valigned <- gtable_combine(g1,g2, along=2)
valigned<- gtable_add_grob(valigned ,
grobs = rectGrob(gp = gpar(fill = NA, lwd = 3)),
t = 1, b = nrow(valigned), l = 1, r = ncol(valigned))

Related

using a grouping variable and geom_rect

I want to show covered ranges (including overlaps) and (after some failures with stacked bar plots) I chose geom_rect. The following code works well for one type.
library(tidyverse)
# create dummy data
foo <- tibble(start = c(1, 150, 140, 75, 300),
end = c(150, 180, 170, 160, 400))
ggplot() +
geom_rect(data = foo, aes(xmin = start, xmax = end, ymin = 0, ymax = 1), fill = "green", linetype = "blank", alpha = 0.3) +
geom_rect(data = foo, aes(xmin = 1, xmax = max(end), ymin = 0, ymax = 1), fill = NA, colour = "black") +
scale_y_continuous(name = "", breaks = NULL, limits = c(0, 1)) +
scale_x_continuous(name = "", breaks = NULL) +
theme_minimal() +
theme(panel.grid = element_blank())
If I add more data (only one more type, but in the original data I do have some more) like below, I can add the data "by hand", i.e. add two lines of code for each type, but I'm looking for a way to do this by grouping, but didn't succeed.
foo <- foo %>%
mutate(type = "A", .before = 1)
bar <- tibble(type = "B",
start = c(1, 30, 40, 100, 150, 200, 310),
end = c(20, 50, 100, 120, 200, 300, 380))
foo <- bind_rows(foo, bar)
ggplot() +
geom_rect(data = foo %>% filter(type == "A"), aes(xmin = start, xmax = end, ymin = 0, ymax = 1), fill = "green", linetype = "blank", alpha = 0.3) +
geom_rect(data = foo, aes(xmin = 1, xmax = max(end), ymin = 0, ymax = 1), fill = NA, colour = "black") +
geom_rect(data = foo %>% filter(type == "B"), aes(xmin = start, xmax = end, ymin = 2, ymax = 3), fill = "green", linetype = "blank", alpha = 0.3) +
geom_rect(data = foo, aes(xmin = 1, xmax = max(end), ymin = 2, ymax = 3), fill = NA, colour = "black") +
scale_y_continuous(name = "", breaks = NULL, limits = c(0, 3)) +
scale_x_continuous(name = "", breaks = NULL) +
geom_text(aes(x = c(0, 0), y = c(0.5, 2.5), label = c("A", "B")), size = 4, hjust = 2) +
theme_minimal() +
theme(panel.grid = element_blank())
So, the graph already looks the way I want, but I'd prefer to get here by using grouping (or any other non-manual way).
Maybe there's also a different geom or method to get this kind of graph?
You can write a small helper function that positions a categorical value in continuous space. Example below.
helper <- function(x) {(match(x, sort(unique(x))) - 1) * 2}
ggplot(foo) +
geom_rect(
aes(xmin = start, xmax = end,
ymin = helper(type),
ymax = helper(type) + 1),
fill = "green", linetype = "blank", alpha = 0.3
) +
geom_rect(
aes(xmin = min(start), xmax = max(end),
ymin = helper(type),
ymax = helper(type) + 1),
fill = NA, colour = "black"
) +
scale_y_continuous(name = "", breaks = NULL, limits = c(0, 3)) +
scale_x_continuous(name = "", breaks = NULL) +
annotate(
"text", x = c(0, 0), y = c(0.5, 2.5), label = c("A", "B"),
size = 4, hjust = 2
) +
theme_minimal() +
theme(panel.grid = element_blank())

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 ?

How to add areas under a geom_line?

I want to display on the same graph a geom_line and the state (which is in a vector).
The data for example:
Timestamp;Value;State
20190618;1.2;UP
20190619;1.0;DOWN
20190620;1.1;UP
...
This is an example of what i'd like to obtain:
I know how to geom_line, i've already try to use geom_area but none of these try succeed.
Any help ? :-)
library(tidyverse)
ggplot(df) +
geom_rect(aes(xmin = Timestamp, xmax = lead(Timestamp),
ymin = 0, ymax = Inf,
fill = State), alpha = 0.2) +
geom_step(aes(Timestamp, Value))
# based on your data, after converting into table with Timestamp as a date
df <- structure(list(Timestamp = structure(c(18065, 18066, 18067), class = "Date"),
Value = c(1.2, 1, 1.1), State = c("UP", "DOWN", "UP")),
class = "data.frame", row.names = c(NA, -3L))
Is this what you are looking for (alternative to geom_rect)?
Prepare example data
x <- 1:5
y <- c(4,1,6,2,2)
plot.df <- data.frame(Timestamp=x, Value=y)
Code for the plot:
library(ggplot2)
ggplot(plot.df, aes(x=Timestamp,y=Value)) +
annotate("rect", xmin = 1, xmax = 2, ymin = -Inf, ymax = Inf,
alpha = .2, fill = "green") +
annotate("rect", xmin = 2, xmax = 3, ymin = -Inf, ymax = Inf,
alpha = .2, fill = "red") +
annotate("rect", xmin = 3, xmax = 4, ymin = -Inf, ymax = Inf,
alpha = .2, fill = "green") +
geom_step(direction = "h") +
theme_classic()

ggplot background in three different colours with geom_rect not working - with data and all code

Reproducible data:
df <- data.frame(cbind("Thriving" = c(2, 2, NA, runif(9, 2.0, 5.0)), "Performance" = c(2, 3.5, 2.3, 4.2, NA, runif(7, 1.9, 6.9)), "Mastery_Climate" = c(runif(10, 2.2, 6.5), NA, 2.3), "Competitive_Climate" = c(NA, runif(4, 1.0, 3.6), NA, NA, runif(5, 1.5, 2.8)), "Collaboration" = c(runif(8, 2.2, 7.0), NA, NA, 5.5, 2.1)))
With this data I want to create bloxplots using the following command with the packages ggplot2 and tidyr:
df %>%
gather(key = "variable", value = "value") -> n
n$variable <- factor(n$variable, levels = c("Thriving", "Performance", "Mastery_Climate", "Competitive_Climate", "Collaboration"))
ggplot(data = n, aes(y = value, x = variable)) + stat_summary(fun.data = min.mean.sd.max, geom = "boxplot", col = "#323232", fill = "#EFC76C") +
coord_flip() + scale_y_continuous(breaks = c(1, 2, 3, 4, 5, 6, 7)) +
expand_limits(y = c(1, 7)) +
labs(x = "", y = "") +
theme(text = element_text(size = 12), panel.background = element_rect(fill = "#EAEDED")) +
theme(plot.margin=unit(c(0, 2, 0, 1.8),"cm"))
The function used in stat_summary is as follows:
min.mean.sd.max <- function(x) {
r <- c(min(x), mean(x) - sd(x), mean(x), mean(x) + sd(x), max(x))
names(r) <- c("ymin", "lower", "middle", "upper", "ymax")
r
}
Now, HERE IT COMES: everything works beautifully, however, now I would like to colour the background in three different colours, green, yellow and red. I know that I have to use geom_rect for that. However, in order to have the boxplots in the foreground, I need to pass the geom_rect argument first - but this breaks my code:
df %>%
gather(key = "variable", value = "value") -> n
n$variable <- factor(n$variable, levels = c("Thriving", "Performance", "Mastery_Climate", "Competitive_Climate", "Collaboration"))
ggplot(data = n, aes(y = value, x = variable)) +
geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = 3, fill = "green"), alpha = .01) +
geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = 3, ymax = 5, fill = "yellow"), alpha = .01) +
geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = 5, ymax = Inf, fill = "red"), alpha = .01) +
stat_summary(fun.data = min.mean.sd.max, geom = "boxplot", col = "#323232", fill = "#EFC76C") +
coord_flip() + scale_y_continuous(breaks = c(1, 2, 3, 4, 5, 6, 7)) +
expand_limits(y = c(1, 7)) +
labs(x = "", y = "") +
theme(text = element_text(size = 12), panel.background = element_rect(fill = "#EAEDED")) +
theme(plot.margin=unit(c(0, 2, 0, 1.8),"cm"))
As you can see, I get the error "Error: Discrete value supplied to continuous scale". From research I understand that this is because I needed to change the sequence and it now is a problem that the x-variable is a factor. However, I have been unable to solve this.
It would be great if all the other code could stay the same, it took me ages to put it together. Also, once the boxplots are in the foreground, it would be great if the grid behind would still be visible. Furthermore, I was so confused by the fill in geom_rect, I put in "green" and I get pink, or I put "yellow" and get blue - no clue why.
In any case, any help is very much appreciated. Many greetings!
Edit: Updated answer with better shading control
I think this approach is more idiomatic to ggplot: this puts the shading into a separate table with numeric y values. In a modified ggplot call, all the y values are mapped as numeric values, but the labels for those values are swapped out in the scale_y_continuous line.
rects <- data.frame(xmin = -Inf,
xmax = Inf,
ymin = c(0,3,5),
ymax = c(3,5,Inf),
fill = c("green", "yellow", "red"))
ggplot(data = n, aes(y = value, x = as.numeric(variable))) +
geom_rect(data = rects, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = fill),
# Control the shading opacity here.
inherit.aes = FALSE, alpha = 0.15) +
stat_summary(fun.data = min.mean.sd.max, geom = "boxplot", col = "#323232", fill = "#EFC76C") +
scale_fill_identity() +
scale_x_continuous(breaks = as.numeric(unique(n$variable)), minor_breaks = NULL,
labels = unique(n$variable)) +
scale_y_continuous(breaks = c(1, 2, 3, 4, 5, 6, 7)) +
expand_limits(y = c(1, 7)) +
coord_flip() +
labs(x = "", y = "") +
theme(text = element_text(size = 12), panel.background = element_rect(fill = "#EAEDED")) +
theme(plot.margin=unit(c(0, 2, 0, 1.8),"cm"))
Original answer
geom_rect's coordinates should be pulled outside of the aes() call, and then I get a working solution. However, one problem with this approach is that the background rectangles are actually getting drawn once for each element in the source data, which is why the colors are so bright even with alpha = 0.01.
ggplot(data = n, aes(y = value, x = variable)) +
geom_rect(xmin = -Inf, xmax = Inf, ymin = 0, ymax = 3, fill = "green", alpha = .005) +
geom_rect(xmin = -Inf, xmax = Inf, ymin = 3, ymax = 5, fill = "yellow", alpha = .005) +
geom_rect(xmin = -Inf, xmax = Inf, ymin = 5, ymax = 7, fill = "red", alpha = .005) +
stat_summary(fun.data = min.mean.sd.max, geom = "boxplot", col = "#323232", fill = "#EFC76C") +
coord_flip() + scale_y_continuous(breaks = c(1, 2, 3, 4, 5, 6, 7)) +
expand_limits(y = c(1, 7)) +
labs(x = "", y = "") +
theme(text = element_text(size = 12), panel.background = element_rect(fill = "#EAEDED")) +
theme(plot.margin=unit(c(0, 2, 0, 1.8),"cm"))

Resources