Multiple 2D background plots in RGL - r

I'm trying to put multiple background legends on an rgl plot (in my real-world example, one for lines and one for points), and I would like them to be in different corners of the screen. It seems that the default behavior of rgl is to replace an older legend when a new one is called. The following code, modified from the rgl legend3d example, illustrates this:
library(rgl)
x <- rnorm(100)
y <- rnorm(100)
z <- rnorm(100)
open3d()
par3d(windowRect = c(100, 100, 612, 612))
plot3d(x, y, z)
legend3d(x = 0, y = 0, xjust = 0, yjust = 0, legend = c("2D", "3D"), pch = c(1, 16))
legend3d(x = 1, y = 0, xjust = 1, yjust = 0, legend = c("2D", "3D"), pch = c(1, 16))
What can I do to work around this behavior and get multiple 2D graphics to appear?

legend3d() makes a background using legend() after plot(). So it can't make multiple legends. It would be better to use bgplot3d().
open3d()
par3d(windowRect = c(100, 100, 612, 612))
plot3d(x, y, z)
bgplot3d({
par(mar = c(0, 0, 0, 0))
plot(0, 0, type = "n", xlim = 0:1, ylim = 0:1, xaxs = "i",
yaxs = "i", axes = FALSE, bty = "n")
legend(x = 0, y = 0, xjust = 0, yjust = 0, legend = c("2D", "3D"), pch = c(1, 16))
legend(x = 1, y = 0, xjust = 1, yjust = 0, legend = c("2D", "3D"), pch = c(1, 16))
})

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?

R - How do I line up axes between a boxplot and matplot?

I have created a side-by-side plot in R where both plots are supposed to use the same y-axis. However, the plot on the left is a boxplot and the plot on the right is a matplot and in both plots I have set the same y-axis range ylim = c(0, YMAX). Unfortunately, as you can see below, these plots do not appear to use the same layout range --- the barplot takes the range right to the edges of the axis whereas the matplot has a buffer at each edge of the axis. Consequently, the y-axes on the plots do not line up as intended.
#Create layout for plot
LAYOUT <- matrix(c(rep(1, 2), 2:3), nrow = 2, ncol = 2, byrow = TRUE);
layout(LAYOUT, heights = c(0.1, 1));
#Create plot matrix
par(mar = c(0.5, 2.1, 0.5, 2.1), mgp = c(3, 1, 0), las = 0);
plot.new();
text(0.5,0.5, 'Barplot and Violin Plot', cex = 1.2, font = 2);
par(mar = c(5.1, 4.1, 2.1, 2.1), mgp = c(3, 1, 0), las = 0);
#Generate data for plot
x <- 1:100
y <- rchisq(100, df = 40);
#Generate plots
DENS <- density(y);
YMAX <- 1.4*max(y);
barplot(y, names.arg = x, ylim = c(0, YMAX));
matplot(x = cbind(-DENS$y, DENS$y), y = DENS$x,
type = c('l', 'l'), lty = c(1, 1),
col = c('black', 'black'),
xlim = c(-max(DENS$y), max(DENS$y)),
ylim = c(0, YMAX),
xlab = 'Density', ylab = '');
How do I adjust this plot to line up the y-axes? (Ideally I would like the plot on the right to put the ticks right to the edge of the axis just as is the case on the left.)
The comment by user20650 solves my problem, so I am going to take the liberty of expanding it into a larger answer and linking to some documentation I found on the problem. According to some lecture notes on the base graphics parameters, some of the base plots in R add a 6% buffer beyond the specified axis range by default. The commands xasx = 'i' and yasx = 'i' inhibit this buffer (on the x and y axes respectively), so that the axis limits go right to the edge of the axis.
Applying this solution to the y-axis in the present problem (we do not apply it to the x-axis, since we want to retain the buffer on that axis) gives the following commands and plot. As can be seen from the plot, the y-axes in the two plots now line up correctly. Hooray!
#Create layout for plot
LAYOUT <- matrix(c(rep(1, 2), 2:3), nrow = 2, ncol = 2, byrow = TRUE);
layout(LAYOUT, heights = c(0.1, 1));
#Create plot matrix
par(mar = c(0.5, 2.1, 0.5, 2.1), mgp = c(3, 1, 0), las = 0);
plot.new();
text(0.5,0.5, 'Barplot and Violin Plot', cex = 1.2, font = 2);
par(mar = c(5.1, 4.1, 2.1, 2.1), mgp = c(3, 1, 0), las = 0);
#Generate data for plot
x <- 1:100
y <- rchisq(100, df = 40);
#Generate plots
DENS <- density(y);
YMAX <- 1.4*max(y);
barplot(y, names.arg = x, ylim = c(0, YMAX));
matplot(x = cbind(-DENS$y, DENS$y), y = DENS$x, yaxs = 'i',
type = c('l', 'l'), lty = c(1, 1),
col = c('black', 'black'),
xlim = c(-max(DENS$y), max(DENS$y)),
ylim = c(0, YMAX),
xlab = 'Density', ylab = '');

how to confine plot region at exactly area

For example, I would like to plot a box with grids inside, the code show below:
plot(rnorm(10), rnorm(10), type = "n", asp = 1, xlim = c(0, 1), ylim = c(0, 1), axes = FALSE, pty = "s", bty = "o", xlab = "", ylab = "")
abline(h = seq(0, 1, 0.2), v = seq(0, 1, 0.2), col = "lightgray")
abline(a = 0, b = 1, col = "lightgray")
axis(1, seq(0, 1, 0.2), seq(0, 1, 0.2), pos = 0)
axis(2, seq(0, 1, 0.2), seq(0, 1, 0.2), pos = 0)
But the lines exceed the area (0, 0) to (1, 1), just like box with whisker. It may be the problem with plot region, and how can I confine the plot region to exactly area for example from (0, 0) to (1, 1)?
Thanks a lot!
plot(rnorm(10), rnorm(10), type = "n", asp = 1, xlim = c(0, 1), ylim = c(0, 1),
axes = FALSE, pty = "s", bty = "o", xlab = "", ylab = "")
axis(1, seq(0, 1, 0.2), seq(0, 1, 0.2), pos = 0)
axis(2, seq(0, 1, 0.2), seq(0, 1, 0.2), pos = 0, las=1)
You can use clip to prevent annotations extending beyond the clip region. The four arguments determine the two coordinates of the rectangle for clipping.
clip(0,1,0,1)
abline(h = seq(0, 1, 0.2), v = seq(0, 1, 0.2), col = "lightgray")
abline(a = 0, b = 1, col = "lightgray")

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.

Align plot with barplot in R

I want to display two plots with the same x-values above each other. But the plots don't align.
How can I align them?
Code:
dat <- data.frame(d = LETTERS[1:5], c = c(39, 371, 389, 378, 790), r = c(39,
332, 18, -11, 412))
par(mfrow=c(2,1))
plot(dat$c, type = "s", ylim = c(0, max(dat$c)), xlab = "", ylab = "", axes = FALSE, col = "#4572a7", lwd = 2)
axis(1, at = c(1:length(dat$c)), labels = dat$d, lty = 0)
axis(2, lty = 0, las = 1)
barplot(dat$r, names.arg = dat$d, col = "#008000", border = NA, axes = FALSE)
axis(2, lty = 0, las = 1)
abline(h = 0, col = "#bbbbbb")
We need to get the x-coordinates of the center of each bar and use those coordinates as the x-values of the first plot. We also need to set the same xlim values for each plot:
# Get x coordinates of center of each bar
pr = barplot(dat$r, names.arg = dat$d, col = "#008000", border = NA, axes = FALSE,
plot=FALSE)
par(mfrow=c(2,1))
# Apply the x coordinates we just calculated to both graphs and give both
# graphs the same xlim values
plot(pr, dat$c, type = "s", ylim = c(0, max(dat$c)), xlab = "", ylab = "", axes = FALSE,
col = "#4572a7", lwd = 2, xlim=range(pr) + c(-0.5,0.5))
axis(1, at = pr, labels = dat$d, lty = 0)
axis(2, lty = 0, las = 1)
barplot(dat$r, names.arg = dat$d, col = "#008000", border = NA, axes = FALSE,
xlim=range(pr) + c(-0.5,0.5))
axis(2, lty = 0, las = 1)

Resources