It Is Possible to Create Inset Graphs

It is possible to create inset graphs?

Section 8.4 of the book explains how to do this. The trick is to use the grid package's viewports.

#Any old plot
a_plot <- ggplot(cars, aes(speed, dist)) + geom_line()

#A viewport taking up a fraction of the plot area
vp <- viewport(width = 0.4, height = 0.4, x = 0.8, y = 0.2)

#Just draw the plot twice
png("test.png")
print(a_plot)
print(a_plot, vp = vp)
dev.off()

How can you get ggplot2 to display an inset figure when the main one has a log scale?

With a log scale, simply use the exponent rather than the absolute value to specify coordinates. So, in this example, use 0 < x < 1 since the scale runs from 1e0 to 1e1:

p = qplot(1:10, 1:10, log='x')
g = ggplotGrob(qplot(1, 1))
p + annotation_custom(grob = g, xmin = 0.3, xmax = 0.9, ymin = 6, ymax = 10)

Produce an inset in each facet of an R ggplot while preserving colours of the original facet content

Here is a solution based on Z. Lin's answer, but using ggforce::facet_wrap_paginate() to do the filtering and keeping colourscales consistent.

First, we can make the 'root' plot containing all the data with no facetting.

library(ggpmisc)
library(tibble)
library(dplyr)

n_replicates <- c(rep(1:10,15),rep(seq(10,100,10),15),rep(seq(100,1000,100),15),rep(seq(1000,10000,1000),15))
sim_years <- rep(sort(rep((1:15),10)),4)
sd_data <- rep (NA,600)
for (i in 1:600) {
sd_data[i]<-rnorm(1,mean=exp(0.1 * sim_years[i]), sd= 1/n_replicates[i])
}
max_rep <- sort(rep(c(10,100,1000,10000),150))
data_frame <- cbind.data.frame(n_replicates,sim_years,sd_data,max_rep)


my_breaks = c(2, 10, 100, 1000, 10000)
facet_names <- c(
`10` = "2, 3, ..., 10 replicates",
`100` = "10, 20, ..., 100 replicates",
`1000` = "100, 200, ..., 1000 replicates",
`10000` = "1000, 2000, ..., 10000 replicates"
)

base <- ggplot(data=data_frame,
aes(x=sim_years,y=sd_data,group =n_replicates, col=n_replicates)) +
geom_line() +
theme_bw() +
scale_colour_gradientn(
name = "number of replicates",
trans = "log10", breaks = my_breaks,
labels = my_breaks, colours = rainbow(20)
) +
labs(title ="", x = "year", y = "sd")

Next, the main plot will be just the root plot with facet_wrap().

main <- base + facet_wrap(~ max_rep, ncol = 2, labeller = as_labeller(facet_names))

Then the new part is to use facet_wrap_paginate with nrow = 1 and ncol = 1 for every max_rep, which we'll use as insets. The nice thing is that this does the filtering and it keeps colour scales consistent with the root plot.

nmax_rep <- length(unique(data_frame$max_rep))

insets <- lapply(seq_len(nmax_rep), function(i) {
base + ggforce::facet_wrap_paginate(~ max_rep, nrow = 1, ncol = 1, page = i) +
coord_cartesian(xlim = c(12, 14), ylim = c(3, 4)) +
guides(colour = "none", x = "none", y = "none") +
theme(strip.background = element_blank(),
strip.text = element_blank(),
axis.title = element_blank(),
plot.background = element_blank())
})
insets <- tibble(x = rep(0.01, nmax_rep),
y = rep(10.01, nmax_rep),
plot = insets,
max_rep = unique(data_frame$max_rep))

main +
geom_plot_npc(data = insets,
aes(npcx = x, npcy = y, label = plot,
vp.width = 0.3, vp.height = 0.6)) +
annotate(geom = "rect",
xmin = 12, xmax = 14, ymin = 3, ymax = 4,
linetype = "dotted", fill = NA, colour = "black")

Sample Image

Created on 2020-12-15 by the reprex package (v0.3.0)

How to add different graphs (as an inset) in another python graph

There's more than one way do to this, depending on the relationship that you want the inset to have.

If you just want to inset a graph that has no set relationship with the bigger graph, just do something like:

import matplotlib.pyplot as plt

fig, ax1 = plt.subplots()

# These are in unitless percentages of the figure size. (0,0 is bottom left)
left, bottom, width, height = [0.25, 0.6, 0.2, 0.2]
ax2 = fig.add_axes([left, bottom, width, height])

ax1.plot(range(10), color='red')
ax2.plot(range(6)[::-1], color='green')

plt.show()

Sample Image

If you want to have some sort of relationship between the two, have a look at some of the examples here: http://matplotlib.org/1.3.1/mpl_toolkits/axes_grid/users/overview.html#insetlocator

This is useful if you want the inset to be a "zoomed in" version, (say, at exactly twice the scale of the original) that will automatically update as you pan/zoom interactively.

For simple insets, though, just create a new axes as I showed in the example above.

ggplot2 add two plots in grid.arrange with an inset in the second one in R

a_plot <- ggplot(cars, aes(speed, dist)) + geom_line()
b_plot <- a_plot + annotation_custom(grob = rectGrob(),
xmin = 15, xmax = Inf, ymin=-Inf, ymax=25)


grid.arrange(a_plot, b_plot, ncol=2)

Sample Image

Plot zoomed inset plot of a plot with square and lines

Maybe the following code does what the question asks for. Or, at least, it gives an idea of how to solve the problem.

The region zoomed in is displayed with geom_path drawing a rectangle and the connecting lines with geom_line. To do this two new data sets giving the square's vertices and the lines' end points are created.

polydata <- data.frame(x = c(7.9, 10.1, 10.1, 7.9, 7.9),
y = c(7.9, 7.9, 10.1, 10.1, 7.9))
linedata <- data.frame(x = c(7.9, 7, 10.1, 10),
y = c(7.9, 5, 7.9, 5),
id = c("a", "a", "b", "b"))
p +
geom_path(data = polydata, aes(x, y)) +
geom_line(data = linedata, aes(x, y, group = id),
linetype = "solid") +
annotation_custom(
grob = ggplotGrob(g),
xmin = 7,
xmax = 10,
ymin = 1,
ymax = 5
)

Sample Image

If the inset is redefined with plot.background taking custom values, the result can be made prettier.

g <-
p +
coord_cartesian(ylim = c(8, 10), xlim = c(8, 10)) +
theme(axis.title.x = element_blank(),
axis.title.y = element_blank(),
plot.background = element_rect(colour = "black", fill = NA, size = 1))

Sample Image

In R, how can I store an inset graph for later arranging it with grid.arrange?

you could use annotation_custom or edit the gtable instead of printing to different viewports.

gm <- ggplotGrob(main_plot)
gs <- ggplotGrob(sub_plot)

library(gtable)
library(grid)
panel.id <- 1
panel <- gm$layout[gm$layout$name == "panel",][panel.id,]

inset <- grobTree(gs, vp=viewport(width=unit(1,"in"), x=0.8, y=0.8,
height=unit(1,"in")))
gm <- gtable_add_grob(gm, inset, l=panel$l, t=panel$t)
grid.newpage()
grid.draw(gm)

Sample Image



Related Topics



Leave a reply



Submit