Extract plotting region coordinates for grid.picture() in R - r

Background
I am plotting the following image:
Using this code:
par(mfrow = c(2, 2),
mar = c(2, 2, 2, 2))
plot(1, col = "red", pch = 15)
plot(1, col = "blue", pch = 15)
plot(1, col = "orange", pch = 15)
plot(1, col = "purple", pch = 15)
I'd like to add an external postscript file using grImport (sample data included):
library(grImport)
#PostScriptTrace("drawing.ps")
#pic <- readPicture("drawing.ps.xml")
# generated with dput()
pic <- new("Picture",
paths = list(path = new("PictureFill", rule = "nonzero",
x = c(move = 0, line = 1315.47, line = 1315.47, line = 0,
line = 0),
y = c(move = 1080, line = 1080, line = 7.37891,
line = 7.37891, line = 1080),
rgb = "#D0D1E6", lty = numeric(0),
lwd = 10, lineend = 1, linejoin = 1, linemitre = 10)),
summary = new("PictureSummary",
numPaths = 1, xscale = c(xmin = 0, xmax = 1315.47),
yscale = c(ymin = 7.37891, ymax = 1080)))
grid.picture(pic)
This just puts the ps image filling the entire plotting device:
Question
I would like the violet square to plot exactly on top of one of the plotting regions (let's say top left).
How do I extract the coordinates of the first plot() in the reference frame of the entire device?
Once I have those, how to correctly use the coordinates in grid.picture()?

Related

Polygon inscribed into circles without ggplot2 or fmsb package

I want to create some sort of radar chart but without using ggplot2 or fmsb.
Sample chart:
d1 <- 1:10
names(d1) <- LETTERS[1:10]
rChart <- function(N = 7, R = 1, border = NA, density = NA, angle = 45,
col = rgb(1, 0, 0, 0.5), lty = 2, lwd = 1){
if (N >=3){
alpha <- c(0, 2*pi*(1:N)/N)
x <- R*cos(alpha)
y <- R*sin(alpha)
if (length(dev.list()) == 0){
plot(x, y, type="n")
}
polygon(x, y, col = col, border = border, density = density, angle = angle)
lines(x, y, lty = lty, lwd = lwd, col = col)
}
}
# drawing two circles in one plot
rChart(N = 100, R = 8, density = 10, col = rgb(0, 1, 0, 0.4), lty = 2, lwd = 3)
rChart(N = 100, R = 6, density = 10, col = rgb(0, 1, 0, 0.4), lty = 2, lwd = 3)
Can I implement for loop to create polygon inscribed into circles and then place labels similiar as in the example above?

How to plot filled boxed around line and point in legend?

Some data
dummy.dt <- data.frame(c(1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1000))
plot(dummy.dt, type="n", xlab="x" , ylab="y", xaxt = "n", log = "y")
legend("top", inset=.02, title="legend",
c("1", "2"),
pch = c(1, 1),
lty = c(1, 1),
col=c("blue", "orange"),
fill=c(rgb(red = 200, green = 200, blue = 200, maxColorValue = 255, alpha = 50), rgb(red = 100, green = 100, blue = 0, maxColorValue = 100, alpha = 50))
)
The result looks like this:
The result I´d like to receive would be a filled box all around the lines.
How to manipulate the size of the filled box that is created by fill?
In the first alternative, we keep the original length of the line segments and the corresponding 'long boxes' are made from lines. Create one legend with thick lines (the 'boxes'). Add a second legend on top with the thin lines and points:
plot(1)
# "filled boxes" made of lines
legend("top", inset = 0.02, legend = 1:2, title = "legend",
lty = 1, lwd = 10, box.col = "white",
pch = NA,
col = c("grey90", "yellow"))
# lines and points
legend("top", inset = 0.02, legend = 1:2, title = "legend",
lty = 1, lwd = 1, bty = "n",
pch = 1,
col = c("blue", "orange"))
A second possibility is to decrease the length of the line segments using seg.len. Then boxes are made from points. Please note that we need to specify the same lwd and seg.len in both legend calls, i.e. also in the call for the 'boxes' where lty = 0.
plot(1)
# "filled boxes" made of points
legend("top", inset = 0.02, legend = 1:2, title = "legend",
lty = 0, lwd = 1, seg.len = 1,
pch = 15, pt.cex = 2,
col = c("grey90", "yellow"))
# lines & points
legend("top", inset = 0.02, legend = 1:2, title = "legend",
lty = 1, lwd = 1, seg.len = 1,
pch = 1, bty = "n",
col = c("blue", "orange"))
It's not clear why you need fillat all. If you leave it out you will get only the lines plus the point character distinguished by color:
legend("top", inset=0.2, title="legend",
c("1", "2"),
pch = c(1, 1),
lty = c(1, 1),
col=c("blue", "orange")
# fill=c(rgb(red = 200, green = 200, blue = 200, maxColorValue = 255, alpha = 50),
# rgb(red = 100, green = 100, blue = 0, maxColorValue = 100, alpha = 50)
)

R boxplot; center the axis labels under the tick marks

I plotted a dataframe (16700 obs. of 6 variables) using the following code:
labels <–c("X2137_Fe20","X2137_FeXS","vtc1_Fe20",
"vtc1_FeXS","VTC1c_Fe20","VTC1c_FeXS") #labels x axis
[1]col <- c("chartreuse3", "chocolate2", "chartreuse3", "chocolate2",
"chartreuse3", "chocolate2") #colors
#Plot
boxplot(CVtable,
outline = FALSE,
ylim = c(-0.5,70),
main="CV Replicas",
ylab="RSD(%)",
range = 1.5,
width = c(9,9,9,9,9,9),
plot = TRUE,
col = col,
par (mar = c(5,4.5,5,0.5) + 0.1),
par(cex.lab=2),
par(cex.axis=1.7),
notch = TRUE,
labels = labels)
dev.off()
This is the result
I like this box plot, but there are a couple of things I would like to adjust. I need to keep this font size for the x axis labels, but as you can see the labels are too big and part of them is missed. The solution is to rotate them 45 degrees, but I do not manage to find an easy code to insert in my script.
I tried to delete the original axes (axes=FALSE), then setting new ones by
boxplot(CVtable,
outline = FALSE,
ylim = c(0.5,70),
ylab="RSD(%)",
range = 1.5,
width = c(9,9,9,9,9,9),
plot = TRUE,
col = col,
par (mar = c(5,4.5,5,0.5) + 0.1),
notch = TRUE,
par(cex.lab=1.7),
axes=FALSE)
axis(1, at = c(1,2,3,4,5,6), labels = F, tick = 2, line = NA,
pos = -1, outer = F, font = 3, lty = "solid",
lwd = 2, lwd.ticks = 3, col = NULL, col.ticks = NULL,
hadj = NA, padj = 0)
axis(2, at = c(0,10,20,30,40,50,60,70) , labels =
c(0,10,20,30,40,50,60,70), tick = 2, line = NA,
pos = 0.5, outer = FALSE, font = 1, lty = "solid",
lwd = 2, lwd.ticks = 3, col = NULL, col.ticks = NULL,
hadj = NA, padj = 0, par(cex.lab=1.5))
text(x=c(1,2,3,4,5,6),
y=par()$usr[3]-0.1*(par()$usr[4]-par()$usr[3]),
labels=labels, srt=45, adj=1, xpd=TRUE, par(cex.lab=2))
and this is the output: img2
Well, I do not know how to center my labels under the tick marks and how to extend the x axis to the origin of the graph (left) and to the end of the last box (right). Moreover, the argument par(cex.lab=2) to fix the x axis labels font size seems no longer working in that string.
Any good suggestion?
PS: this is my 1st post, if any needed info is missed, please leave a comment and I will reply as soon as I can. Thank you!
I made it myself:
#RSD
boxplot(CVtable[1:6],
outline = FALSE,
ylim = c(0.5,70),
ylab="RSD(%)",
range = 1.5,
width = c(9,9,9,9,9,9),
plot = TRUE,
col = col,
par (mar = c(7,4.5,1,0.5) + 0.1),
notch = TRUE,
par(cex.lab=1.7),
axes=FALSE)
axis(1, at = c(0.5,1,2,3,4,5,6,7), labels = F, tick = 2, line = NA,
pos = -1, outer = F, font = 3, lty = "solid",
lwd = 2, lwd.ticks = 3, col = NULL, col.ticks = NULL,
hadj = NA, padj = 0)
axis(2, at = c(0,10,20,30,40,50,60,70) , labels =
c(0,10,20,30,40,50,60,70), tick = 2, line = NA,
pos = 0.5, outer = FALSE, font = 4, lty = "solid",
lwd = 2, lwd.ticks = 3, col = NULL, col.ticks = NULL,
hadj = NA, padj = 0, par(cex=1.4))
text(x=c(0.7,1.7,2.7,3.7,4.7,5.7),
y=par()$usr[3]-0.14*(par()$usr[4]-par()$usr[3]),
labels=labels, srt=45, adj=0.6, xpd=TRUE, cex=1, font=2)
dev.off()
This is the result:

How to make the trend-line in a scatter plot respect the boundaries of the x-axis?

I am creating a plot where I plot the variable on the X-axis against that on the Y-axis, and I am adding histograms of the variables as well. I have added a trend-line to the plot using abline().
The problem is that it does not appear to respect the xlim = c(0, 20) in the plot region as it extends beyond the limits of the x-axis. I tried playing around with the xpd option, but to no avail. Next I tried fiddling with the different par()options, but found nothing that could help with this issue.
What I want is for the trend-line to be the exact length of the x-axis. Any help is much appreciated. In this particular case the trend-line is almost flat, but the slope will change when I do the same for other variables.
MWE -- NOTE: I am only providing 15 data points to illustrate the issue so the graph will differ from the image provided.
df.data <- data.frame(id = 1:15,
ll = c(-9.53026, -6.50640,-6.50640, -7.68535, -11.80899, -8.42790,
-6.50640, -6.50640, -7.92405, -6.50640, -8.95522, -9.99228,
-10.02286, -8.95969, -6.07313),
aspm = c(4.582104, 0.490244, 0.737765, 0.256699, 1.575931, 1.062693,
1.006984, 0.590355, 1.014370, 0.924855, 0.735989, 0.831025,
1.197886, 1.143220, 0.928068))
str.col.light.blue <- c(rgb(r = 110/255, g = 155/255, b = 225/255))
str.col.dark.blue <- c(rgb(r = 50/255, g = 100/255, b = 185/255))
layout(matrix(c(2, 4, 1, 3), 2, 2, byrow = TRUE), widths = c(5, 2), heights = c(2, 5))
layout.show(4)
par(omi = c(0.1, 0.1, 0.1, 0.1))
par(mar = c(2, 2, 0, 0))
par(mai = c(1, 1, 0, 0))
plot(df.data[, "ll"] ~ df.data[, "aspm"], col = str.col.light.blue,
xlim = c(0, 20), ylim = c(-15, -5), axes = FALSE,
xlab = "X1", ylab = "X2",
cex.lab = 1.25)
abline(a = -8.156670, b = -0.000879, lty = 5, col = "black", lwd = 2, xpd = FALSE)
axis(1, at = seq(0, 20, by = 5), labels = seq(0, 20, by = 5), cex.axis = 1)
axis(2, at = seq(-15, -5, by = 3), labels = seq(-15, -5, by = 3), cex.axis = 1, las = 1)
rect(0, -15, 20, log(1/3)*8, density = 10, angle = 45, lwd = 0.5, col = "gray")
par(mar = c(0, 2, 0, 0))
par(mai = c(0, 1, 0.25, 0))
x.hist <- hist(df.data[, "aspm"], plot = FALSE, breaks = 20)
barplot(x.hist$density, axes = FALSE, horiz = FALSE, space = 0, col = str.col.dark.blue)
par(mar = c(2, 0, 0, 0))
par(mai = c(1, 0, 0, 0.25))
y.hist <- hist(df.data[, "ll"], plot = FALSE, breaks = 20)
barplot(y.hist$density, axes = FALSE, horiz = TRUE, space = 0, col = str.col.dark.blue)
In order to avoid working out the start and end points of the segments, you can program a helper function to do it for you.
linear <- function(x, a, b) a + b*x
Then, I've used your code with the following changes. abline was replaced by segments, with all the graphics parameters you had used in your original call.
x0 <- 0
y0 <- linear(x0, a = -8.156670, b = -0.000879)
x1 <- 20
y1 <- linear(x1, a = -8.156670, b = -0.000879)
segments(x0, y0, x1, y1, lty = 5, col = "black", lwd = 2, xpd = FALSE)
This call to segment was placed where ablinewas.
In the final graph, I see a well behaved segment.

R Lattice: How to add y = x line and y = -x lines on the xy plane in the lattice wireframe function?

I'm doing Person-Environment fit research, and hope to add the P = E and P = -E lines on the xy plane of response surface drawn by Lattice wireframe. Currently, I've got the code are as follows:
PersonIV <- seq(-3, 3, length = 30)
EnvironmentIV <- seq(-3, 3, length = 30)
g.test.data <- expand.grid(PersonIV = PersonIV, EnvironmentIV = EnvironmentIV)
g.test.data$DV <- .5 + .4 * PersonIV + .6 * EnvironmentIV + .9 * PersonIV^2 + .7 * PersonIV * EnvironmentIV - .3 * EnvironmentIV^2
library(lattice)
trellis.par.set("axis.line", list(col = NA))
wireframe(DV ~ PersonIV * EnvironmentIV, g.test.data,
drape = T, screen = list(z = 30, x = -75),
main = "Person - Environment Fit Response Surface",
xlab = list(xlim = c(-3:3), label = "Personal IV", col = "black", font = 1, cex = 1, rot = 15),
ylab = list(label = "Environment IV", ylim = c(-3: 3), font = 1, cex = 1, rot = -42),
zlab = list(label = "DV", zlim = c(0:5), font = 1, cex = 1, rot = 90, lines = T),
scale = list(arrows = F, cex = 1, col = "black", tck = 1),
par.settings = list(box.3d = list(col=c(1,1,NA,NA,1,NA,1,1,1))),
)
Thanks a lot!
Making a custom panel function and passing it to the lattice plotting function (here, wireframe) with the panel argument is a common way to do this. To recreate the existing plot, panel.xyplot is usually used, and to add lines, panel.abline is usually used. Perhaps something like this.
panel=function(...) {panel.xyplot(...); panel.abline(0,1); panel.abline(0,-1)}

Resources