Insert Layer Underneath Existing Layers in Ggplot2 Object

Insert Layer underneath existing layers in ggplot2 object

Thanks @baptiste for pointing me in the right direction. To insert a layer underneath all other layers, just modify the layers element of the plot object.

## For example:
P$layers <- c(geom_boxplot(), P$layers)

Answer to the Bonus Question:

This handy little function inserts a layer at a designated z-level:

insertLayer <- function(P, after=0, ...) {
# P : Plot object
# after : Position where to insert new layers, relative to existing layers
# ... : additional layers, separated by commas (,) instead of plus sign (+)

if (after < 0)
after <- after + length(P$layers)

if (!length(P$layers))
P$layers <- list(...)
else
P$layers <- append(P$layers, list(...), after)

return(P)
}

Insert geom_sf layer underneath existing geom_sf layers

If you look at geom_sf(data=distSF) you'll see that it is a list made up of two elements - you want the first one which contains the layer information, so geom_sf(data = distSF, fill = "gold")[[1]] should work.

districts <- ggplot() +
geom_sf(data = distSF, fill = "gold")

basicIndia$layers <- c(geom_sf(data = distSF, fill = "gold")[[1]], basicIndia$layers)

adding multiple layers to a ggplot with a function

From help("+.gg"):

You can also supply a list, in which case each element of the list will be added in turn.

add_points <- function(x) {
list(geom_point(aes(x = x - 1, y = 0), color = "red"),
geom_point(aes(x = x + 1, y = 0), color = "red"))
}

p + add_points(x = 0)
#works

adding layers in ggplot2 with for loops

ggplot does a bit of lazy evaluation, so in your for loop example i isn't evaluated immediately. If we look at the layers, we can see the i is still there as i, not as 3 and 4 in the respective iterations. When you print the plot, that is when i is evaluated--at whatever value it takes when you print the plot. When can even change i after the loop to cause problems:

aux <- 3:4
p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()

for (i in 1:2) {
p <- p + geom_segment(aes(x = aux[i], y = 0, xend = aux[i], yend = 35), colour = "purple")
}

p$layers
# [[1]]
# geom_point: na.rm = FALSE
# stat_identity: na.rm = FALSE
# position_identity
#
# [[2]]
# mapping: x = ~aux[i], y = 0, xend = ~aux[i], yend = 35
# geom_segment: arrow = NULL, arrow.fill = NULL, lineend = butt, linejoin = round, na.rm = FALSE
# stat_identity: na.rm = FALSE
# position_identity
#
# [[3]]
# mapping: x = ~aux[i], y = 0, xend = ~aux[i], yend = 35
# geom_segment: arrow = NULL, arrow.fill = NULL, lineend = butt, linejoin = round, na.rm = FALSE
# stat_identity: na.rm = FALSE
# position_identity

## changing `i` later can still cause problems:
i = 5
print(p)
# Warning messages:
# 1: Removed 32 rows containing missing values (geom_segment).
# 2: Removed 32 rows containing missing values (geom_segment).

So, no, you can't really use for loops quite like that. There are probably workarounds, but this feels like an XY problem - this isn't how ggplot is intended to be used, so using it this way will be difficult.

It's hard to know what your real use case is, but in this case we could put aux data in a data frame and do it like this (ggplot is made to work with data frames):

ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
geom_segment(
data = data.frame(aux),
aes(x = aux, xend = aux),
y = 0, yend = 35, colour = "purple"
)

Though, for the the special case of vertical lines, we can use geom_vline with the aux vector directly:

ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
geom_vline(xintercept = aux, colour = "purple")

How can I add another layer / new series to a ggplot?

rubies  <- data.frame(carat = c(3, 4, 5), price= c(5000, 5000, 5000))

ggplot(diamonds, aes(carat, price)) +
geom_point() +
geom_point(data = rubies, colour = "red")

Add layers conditionally to a gglplot depending on the value of a function variable

Try appending layers to the ggplot object rather than having one big expression. This way you can add some logic about what layers to add. Note that I couldn't really test this without tsne.meta.

tsnePlotSubcluster <- function(feature = "subcluster", # can be area, age, subcluster
subclust = "cluster_1",
size.grey = 0.25,
size.color = 0.3) {

# params <- plot.params[[celltype]]
# cluster.colors <- color.values[[celltype]]$i

p <- ggplot(tsne.meta) +

# Plot cells in all other subclusters in grey.
geom_point(data = filter(tsne.meta, ! subcluster.merge == subclust),
aes(tSNE_1, tSNE_2, alpha = nGene),
colour = "grey90", size = size.grey)

# a) Highlight subcluster:
# Plot cells from selected subcluster in color.
if(feature == "subclust") {
p <- p + geom_point(data = filter(tsne.meta, subcluster.merge == subclust),
aes(tSNE_1, tSNE_2, color = nGene, alpha = nGene),
size = size.color) +
theme(legend.position = 'none') +
scale_color_viridis_c(option = "plasma", begin = 0.1, end = 0.6)
}
# b) Color subcluster cells by age:
else if(feature == "age") {
p <- p + geom_point(data = filter(tsne.meta, subcluster.merge == subclust),
aes(tSNE_1, tSNE_2, color = Age, alpha = nGene),
size = size.color) +
scale_color_viridis_d(option = "plasma") +
theme(legend.position = 'top')
}

# c) Color subcluster cells by area:
else if(feature == "area") {
p <- p + geom_point(data = filter(tsne.meta, subcluster.merge == subclust),
aes(tSNE_1, tSNE_2, color = area, alpha = nGene),
size = size.color) +
scale_color_viridis_d(option = "viridis") +
theme(legend.position = 'top')
}

p <- p + labs(title = paste(celltype, "|", subclust)) +

theme(plot.subtitle = element_text(color="grey18", size=11, family="Helvetica", face = "plain", hjust = 0.5),
plot.title = element_text(color="grey18", size=12, family="Helvetica", face = "plain"),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.line = element_blank(),
panel.background = element_blank(),
panel.grid = element_blank()
)

return(p)
# png(paste0("tSNE_", celltype, "_", subclust,".png"), height = 5, width = 6, units = 'in', res = 300)
# print(p)
# dev.off()
}

You also may want to look at programmatic aes

Add layers from different datasets

For example:

ggplot() +
geom_point(data=dat,aes(x=x,y=y,colour=z)) +
geom_line(data=dat1,aes(x=x,y=b))

How to determine the geom type of each layer of a ggplot2 object?

ggplot 2.2 update:
If what you want is a character string naming the geom type, you can use:

sapply(p$layers, function(x) class(x$geom)[1])

which yields the first class name for the geom object of each layer. In the OP's example:

[1] "GeomRibbon" "GeomLine" 

The code in the answers above no longer give the results shown for version 2.2 The accepted answer yields two NULL values, and the other answer yields full ggproto objects.



Related Topics



Leave a reply



Submit