I have two plots that I would like to overlay in a particular way. Instead of side by side like when using par(), I would like one to sit inside the other, but be about a quarter the size.
More details: one of my plots is a map, another is a scatterplot with colored quadrants. The colored quadrants represent the colors plotted onto the map, so I would like to inset it nicely in the same plot as the map so that it serves as a legend.
Thanks in advance
Here's an example, although the links in comments point to similar approaches.
Grab a shapefile:
download.file(file.path('http://www.naturalearthdata.com/http/',
'www.naturalearthdata.com/download/50m',
'cultural/ne_50m_admin_1_states_provinces_lakes.zip'),
{f <- tempfile()})
unzip(f, exdir=tempdir())
Plotting:
library(rgdal)
shp <- readOGR(tempdir(), 'ne_50m_admin_1_states_provinces_lakes')
plot(subset(shp, admin=='Australia'),
col=sample(c('#7fc97f', '#beaed4', '#fdc086', '#ffff99'),
9, repl=TRUE))
opar <- par(plt=c(0.75, 0.95, 0.75, 0.95), new=TRUE)
plot.new()
plot.window(xlim=c(0, 1), ylim=c(0, 1), xaxs='i', yaxs='i')
rect(0, 0, 0.5, 0.5, border=NA, col='#7fc97f')
rect(0.5, 0, 1, 0.5, border=NA, col='#beaed4')
rect(0, 0.5, 0.5, 1, border=NA, col='#fdc086')
rect(0.5, 0.5, 1, 1, border=NA, col='#ffff99')
points(runif(100), runif(100), pch=20, cex=0.8)
box(lwd=2)
par(opar)
See plt under ?par for clarification.
This is how I did it in the past
grid.newpage()
vp <- viewport(width = 1, height = 1)
submain <- viewport(width = 0.9, height = 0.9, x = 0.5, y = 1,just=c("center","top"))
print(p, vp = submain)
subvp2 <- viewport(width = 0.2, height = 0.2, x = 0.39, y = 0.35,just=c("right","top"))
print(hi, vp = subvp2)
subvp1 <- viewport(width = 0.28, height = 0.28, x = 0.0, y = 0.1,just=c("left","bottom"))
print(ak, vp = subvp1)
in my case p, ak and hi were gg objects (maps created with ggplot) and I was inserting a small version of each near the main use map (p) - as it is typically done
Related
https://bootstrappers.umassmed.edu/bootstrappers-courses/pastCourses/rCourse_2014-09/resources/helpfulGuides/Rfigurelayout.pdf
The above doc shows plot region, figure region, and device region.
Suppose these regions are mentally mapped to coordinates from 0 (the bottom or the left) to 1 (the top or the right). How to put text in this definition of coordinates on these three regions in basic R, respectively?
I think what you are asking is how to place text anywhere in the plotting window, using proportional device co-ordinates. This is actually how text works in the grid graphic system:
library(grid)
grid.newpage()
grid.draw(rectGrob(gp = gpar(lwd = 2)))
grid.draw(textGrob("(0.1, 0.1)", 0.1, 0.1, gp = gpar(cex = 2, col = "red2")))
grid.draw(textGrob("(0.5, 0.5)", 0.5, 0.5, gp = gpar(cex = 2, col = "blue")))
grid.draw(textGrob("(0.9, 0.9)", 0.9, 0.9, gp = gpar(cex = 2, col = "green2")))
However, if you want to do the same thing in base R graphics, I think you would need to write a wrapper around text that queries the graphics device and converts your device space co:ordinates to user co-ordinates, then draws the text with clipping off.
Here is such a function (called dtext to denote "device text")
dtext <- function(x = 0.5, y = 0.5, label, ...) {
margins <- par("omi") + par("mai")
plotsize <- par("pin")
devsize <- dev.size()
usr_space <- par("usr")
usr_y <- devsize[2] / plotsize[2] * (diff(usr_space[3:4]))
y_min <- usr_space[3] - usr_y * margins[1]/devsize[2]
usr_x <- devsize[1] / plotsize[1] * (diff(usr_space[1:2]))
x_min <- usr_space[1] - usr_x * margins[2]/devsize[1]
text(x = x * usr_x + x_min,
y = y * usr_y + y_min,
label = label,
xpd = NA,
...)
}
This allows:
plot(1:10, 1:10)
dtext(x = 0.1, y = 0.1, label = "(0.1, 0.1)", cex = 2, col = "red2")
dtext(x = 0.5, y = 0.5, label = "(0.5, 0.5)", cex = 2, col = "blue2")
dtext(x = 0.9, y = 0.9, label = "(0.9, 0.9)", cex = 2, col = "green2")
This seems like a pretty useful function, and I'm surprised it doesn't exist already, so thanks for the OP.
Created on 2022-04-02 by the reprex package (v2.0.1)
I need make meteorological maps with package lattice. But i found a problem in comand levelplot(). I can make maps with the comand using a regular label. E.g: Correlation maps with label 0, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35 0.4... In this example the label skip five by five (Fig.1).
h1<- levelplot(var~x*y,data = idw.msk.dfr,contour=F,at=seq(0,0.5,0.05),
par.settings = paleta1,main = "correlation map",
xlab = NULL, ylab = NULL, ylim = c(-60,15), xlim = c(-90,-30))
Figure 1:
But, i need make maps with non-regular values. E.g: 0, 0.1, 0.15, 0.2, 0.22, 0.25, 0.40... When put this values in code, i get this result (Fig.2):
h1<- levelplot(var~x*y,data = idw.msk.dfr,contour=F,at=c(0,0.1,0.15,0.2,0.22,0.25,0.4,0.5),
par.settings = paleta1,main = "correlation map",
xlab = NULL, ylab = NULL, ylim = c(-60,15), xlim = c(-90,-30))
Figure 2
Note that the label of map is very strange and inrregular.
So. How do i solve this problem? I will apreciate your help.
You need to specify a custom colorkey. Add colorkey to the levelplot function.
x <- seq(pi/4, 5 * pi, length = 100)
y <- seq(pi/4, 5 * pi, length = 100)
r <- as.vector(sqrt(outer(x^2, y^2, "+")))
grid <- expand.grid(x=x, y=y)
grid$z <- cos(r^2) * exp(-r/(pi^3))
breaks <- c(0, 0.1, 0.15, 0.2, 0.22, 0.25, 0.4, 0.5)
levelplot(z~x*y, grid, at=breaks)
myColorkey=list(at=breaks, labels=list(at=breaks, labels=breaks))
levelplot(z~x*y, grid, colorkey=myColorkey)
To have the same size for the intervals change the at argument:
ats=seq(0, 0.5, by=0.07)
myColorkey=list(at=ats, labels=list(at=ats, labels=breaks))
levelplot(z~x*y, grid, colorkey=myColorkey)
ENV
R 3.3.1
mini data
rdn<-c(0.8,1.8,2.8)
tdn<-c(1,2,3,4,5,6,7,8,9)
idn<-matrix(c(0.3, 0.3, 0.3, 0.2, 0.2, 0.4, 0.1, 0.1, 0.5, 0, 0.2, 0.5, 0, 0.3, 0.6, 0, 0.4, 0.6, 0, 0.4, 0.6, 0, 0.5, 0.7, 0, 0.5, 0.7), nrow=9, ncol=3, byrow=T)
What I have now:
code
filled.contour(tdn, rdn, idn,
color.palette=colorRampPalette(c("blue","yellow","red")),
plot.title=title(main="Detail", sub="detail",
xlab="t", ylab="lambda"),
plot.axes = { axis(side = 1, at = tdn, labels = tdn)
axis(side = 2, at = rdn, labels = rdn) },
key.title=title(main="ratio"),
key.axes = axis(4, seq(0, 1, by = 0.1)))
Current Result
Problem
The color range is not what I want. There are borders among colors so colors do not change smoothly from deep blue to deep red.
Expected
Question
how to make colors change smoothly like my Expeced figure when plotting in R? How do I remove problems above? And rainbow not works for me either. Thanks.
EDIT
Follow Haboryme's solution
The foreground not disappear.
Close to #setempler answer but you might find it a bit closer to your expected output:
par(fg = NA,col="black")
filled.contour(x=tdn,
y=rdn,
z=idn,
color.palette=colorRampPalette(c("blue","yellow","red")),
plot.title=title(main="Detail", sub="detail",
xlab="t", ylab="lambda"),
nlevels=200,
plot.axes = { axis(side = 1, at = tdn, labels = tdn)
axis(side = 2, at = rdn, labels = rdn) },
key.title=title(main="ratio"),
key.axes = axis(4, seq(0, 1, by = 0.1)))
Unfortunately, filled.contour ...
fixes the number of levels/colours between the plot and key, so experimenting with the nlevels argument (and col instead color.palette) results in a weird output (smoother image, but unreadable key).
In addition, the contour lines cannot be modified. Thus, an increase to 200 levels (from initially 14 in your example) is still 'readable', but higher values generate unwanted side-effects.
Example:
n <- 200
filled.contour(tdn, rdn, idn,
col=colorRampPalette(c("blue","yellow","red"))(n),
levels = seq(0,1,length.out = n),
plot.title=title(main="Detail", sub="detail",
xlab="t", ylab="lambda"),
plot.axes = { axis(side = 1, at = tdn, labels = tdn)
axis(side = 2, at = rdn, labels = rdn) },
key.title=title(main="ratio"),
key.axes = axis(4, seq(0, 1, by = 0.1)))
Output:
Maybe experimenting with lattice::levelplot solves the problem. At least for the legend color key, a higher number of levels does not disturb. But the image is not 'smoothed'.
Example:
library(lattice)
levelplot(idn, row.values = tdn, column.values = rdn, cuts = n, col.regions = colorRampPalette(c("blue","yellow","red"))(n))
Output:
I have succeeded in creating and aligning three scatter-plots in R, using the following code:
par(mfrow = c(3,1))
plot(CGP.GOSL ~ FPT.MAF.GOSL, data = all.locs, main = "A. Place I")
abline(h=c(0.5))
abline(v=c(0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5), lty=2)
plot(CGP.IRE ~ FPT.MAF.IRE, data = all.locs, main = "B. Place II")
abline(h=c(0.5))
abline(v=c(0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5), lty=2)
plot(CGP.BAR ~ FPT.MAF.BAR, data = all.locs, main = "C. Place III")
abline(h=c(0.5))
abline(v=c(0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5), lty=2)
What I would like to do now is save space by having a single Axis label for the x and y axis. I have tried experimenting with the par() function, inserting x and ylab functions, but it seems that as these are not graphical parameters is will not accept them. I suspect the problem lies in where I place this information in the code, as using the xlab and ylab seems to make sense, and I can write x and ylab = "" in the individual plot codes.
I am also struggling to change the position of the main titles so that the appear on the left, to remove the values from the x-axis so that they only show at the bottom of the whole figure, and to arrange the figure so that there is less space.
This figure shows the current layout and the layout I want to achieve:
I am sorry to post so many questions at once. I am very new to R and programming am still finding the helpfiles a bit daunting, although I am getting there. Some suggestions on functions, where to put them and how to use them to achieve some of these aims would be great.
The documentation can be a bit challenging at times. Here's a skeleton for what I think you're looking for:
# 3 rows
par(mfrow=c(3,1))
# tighter margins
par(mar = c(0, 0, 0, 0), oma = c(4, 4, 0.5, 0.5))
# need some data
data(cars)
# 3 plots, no axis junk
plot(cars, ann=FALSE)
plot(cars, ann=FALSE)
plot(cars, ann=FALSE)
# outer labels
mtext("x axis", side = 1, outer = TRUE, cex = 0.7, line = 2.2)
mtext("y axis", side = 2, outer = TRUE, cex = 0.7, line = 2.2)
This answer is based on hrbrmstr's answer, but the result is closer to the requested layout:
# 3 rows
par(mfrow=c(3,1))
# Adjust margins. Each vector element refers to one side of the plot;
# the order is c(bottom, left, top, right). (See ?par)
par(mar = c(2.5, 4.1, 1, 2.1), oma = c(3, 3, 2, 0))
# need some data
data(cars)
# 3 plots. On the first two: Suppress axis labels (ann = FALSE) and
# the x axis (xaxt = "n"), then add the ticks using axis() and the
# title using mtext(). On the last one, do not suppress x axis.
# Note that repeating arguments could be set globally using par().
plot(cars, ann = FALSE, xaxt = "n")
axis(side = 1, labels = FALSE)
mtext(text = "A. Place I", side = 3, at = par("usr")[1], line = 1)
plot(cars, ann=FALSE, xaxt = "n")
axis(side = 1, labels = FALSE)
mtext(text = "B. Place II", side = 3, at = par("usr")[1], line = 1)
plot(cars, ann=FALSE)
mtext(text = "C. Place III", side = 3, at = par("usr")[1], line = 1)
# outer labels
mtext("X Axis label", side = 1, outer = TRUE)
mtext("Y Axis label", side = 2, outer = TRUE)
I want to plot several plots in r, 24 to be exactly in one page. Furthermore, I want the plots to have a rectangular form. However when I use:
par(mfrow = c(6,4),pin = c(2,1))
I get a plot with massive white space wasted, at the bottom and top of the plots. If I try to reduce the outer margin of the plots using:
par(mfrow = c(6,4),pin = c(2,1), oma = c(0,0,0,0))
the result is the same.
You can control for margins, I have you already tried this:
layout(matrix(c(1:24), nrow = 6, byrow = T));par(mfrow = c(6,4),pin = c(2,1), oma = c(0,0,0,0));
for (i in 1:24) { plot(rnorm(100), main = sprintf("%do gráfico", i)) }
You can't set "margin options" and "pin" at once, but can "plt". First par() sets lower y (or x), upper x, and y. Second par() calculates lower x (or y) from "fin" and the aspect ratio, and sets it.
# sets lower y and calculates lower x
par( plt = c( 0, 0.97, 0.22, 0.97) )
par( mfrow=c(6,4), mgp = c(3, 0.5, 0),
plt = c( par("plt")[2] - par("pin")[2] * 2 / 1 / par("fin")[1], par("plt")[2:4]) )
for (i in 1:24) plot(rnorm(100), ann=F)
# sets lower x and calculates lower y
par( plt = c( 0.2, 0.97, 0, 0.97) )
par( mfrow=c(6,4), mgp = c(3, 0.5, 0),
plt = c(par("plt")[1:2], par("plt")[4] - par("pin")[1] * 1 / 2 / par("fin")[2], par("plt")[4]) )
for (i in 1:24) plot(rnorm(100), ann=F)