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 viewport
s.
#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")
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()
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)
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
)
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))
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)
Related Topics
Adaptive Moving Average - Top Performance in R
Changing Line Colors with Ggplot()
Converting Nested List to Dataframe
Adding Space Between Bars in Ggplot2
Subset a Column in Data Frame Based on Another Data Frame/List
Remove All Punctuation Except Apostrophes in R
Dplyr Mutate Rowwise Max of Range of Columns
Twitter, Roauth and Windows: Register Ok, But Certificate Verify Failed
Extract Matrix Column Values by Matrix Column Name
How to Find All Functions in an R Package
Installation of Rodbc/Roracle Packages on Os X Mavericks
How to Add a General Label to Facets in Ggplot2
Sort Columns of a Dataframe by Column Name
Creating a Summary Statistical Table from a Data Frame