I saw the following code in an example of plot3d:
par(mfrow = c(2, 2))
# keep ratios between x- and y (scale = FALSE)
# change ratio between x- and z (expand)
persp3D(z = volcano, x = 1: nrow(volcano), y = 1:ncol(volcano),
expand = 0.3, main = "volcano", facets = FALSE, scale = FALSE,
clab = "height, m", colkey = list(side = 1, length = 0.5))
# ribbon, in x--direction
V <- volcano[, seq(1, ncol(volcano), by = 3)] # lower resolution
ribbon3D(z = V, colkey = list(width = 0.5, length = 0.5,
cex.axis = 0.8, side = 2), clab = "m")
# ribbon, in y-direction
Vy <- volcano[seq(1, nrow(volcano), by = 3), ]
ribbon3D(z = Vy, expand = 0.3, space = 0.3, along = "y",
colkey = list(width = 0.5, length = 0.5, cex.axis = 0.8))
This prints four plots, but they each have their own legend.
I want to create similar 3d histograms, only my "Z" have all the same range, and I want to use just a single legend.
So what I want to do is:
Be able to draw just the legend (so I can save it to a file) for all unified histograms, where it is printed horizontally.
Make all legends in all small plots disappear.
I would also appreciate just an answer to one of these questions.
Related
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 = '');
So I've created a barplot for some data I have with the following code:
plot <- barplot(data,
beside = TRUE,
col = c("red", "blue", "green"),
space = c(0, 0.4),
width = 0.2,
xlim = c(0, 2),
ylim = c(0, 1.1),
legend = c("KNN", "MF1", "MF2"),
args.legend = list(x = 2.7, y = 1.2),
yaxt = 'n',
xpd = TRUE,
srt = 90
)
text(x = plot,
y = data + 0.05,
labels = as.character(round(data, digits = 2)),
srt = 90,
xpd = TRUE
)
I think the plot looks neat, but... It does not fit the region (I think at least). Are there any ways to keep the width of the bars in picture 1 and still show all 8 groups? My solution so far is to reduce the width of the bars as shown in picture 2.
Picture 1
Picture 2
I'm trying to plot a legend in base R with the symbols horizontally and the corresponding labels underneath the symbols on the next row. The legend will be plotted in the margins (not included in example data). Is there a way to use graphical parameters to solve this with the legend() function? Otherwise I will try the text labels, but I prefer a more manageable approach.
I have this example data:
plot(c(1,2,3,4,5), c(1,2,3,4,5), xlim=c(0,5), ylim=c(0,5), main = "", xlab = "", ylab = "")
legendEntries <- c(0.05, 0.1, 0.15, 0.2, 0.25) # which values in legend
legendSizes <- sqrt( legendEntries / pi ) * 10 # calculate pch size
legend(1, 2, title="", horiz = T, legend=legendEntries, col="black", pch=rep(21,5),
pt.bg = "#ff166c", pt.cex = legendSizes, bty = "n")
And want to create something like this:
Thanks!
Paul
(edit: added picture in text and extra info)
You can plot separately points and text.
Something like:
# Make the basic plot
plot(c(1,2,3,4,5), c(1,2,3,4,5), xlim=c(0,5), ylim=c(0,5), main = "", xlab = "", ylab = "")
# set up the legend entries and sizes
legendEntries <- c(0.05, 0.1, 0.15, 0.2, 0.25) # which values in legend
legendSizes <- sqrt( legendEntries / pi ) * 10 # calculate pch size
# plot the legend points
points(y = rep(1, 5), x = seq(3,4, 0.25), pch = 21, cex = sqrt( legendEntries / pi ) * 10,
bg = "#ff166c")
# plot the text
text(y = rep(0.7, 5), x = seq(3,4, 0.25),
labels = legendEntries)
For Plotting outside of the plot region (i.e. on the margins), you can use the xpd parameter as xpd = TRUE:
plot(c(1,2,3,4,5), c(1,2,3,4,5), xlim=c(0,5), ylim=c(0,5), main = "", xlab = "", ylab = "")
legendEntries <- c(0.05, 0.1, 0.15, 0.2, 0.25) # which values in legend
legendSizes <- sqrt( legendEntries / pi ) * 10 # calculate pch size
points(y = rep(-0.8, 5), x = seq(1,2, 0.25), pch = 21, cex = sqrt( legendEntries / pi ) * 10,
bg = "#ff166c", xpd = TRUE)
text(y = rep(-1, 5), x = seq(1,2, 0.25),
labels = legendEntries, xpd = TRUE)
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)}
I'm plotting a cdf of some data, and I've added logarithmic scale on the "x" axis.
The ticks spacing is exactly as I want it to be, but I'd like to be able to add
some tick marks on specific points.
I don't want to change the distribution of the ticks in my plot, from n by n to m by m, I want simply to have, among the ticks from n by n, some further tick marks on some values.
I'd like to have it reflected in both x and y axis, so that I can fit a grid into these new marks throughout the graph.
So far I have the graph, and the grid -- I don't mind about having the grid behind or upon the graph, I just want to add some custom ticks.
# Cumulative Distribuition
pdf("g1_3.pdf")
plot(x = f$V2, y = cumsum(f$V1), log = "x", pch = 3,
xlab = "Frequency", ylab = "P(X <= x)",
panel.first = grid(equilogs = FALSE))
axis(1, at = c(40, 150))
abline(h = 0.6, v = 40, col = "lightgray", lty = 3)
abline(h = 0.6, v = 150, col = "lightgray", lty = 3)
dev.off()
UPDATE: The graph I have so far:
Considering the initial script, and the tips given by #BenBolker, I had to use:
axis(side = 1, at = c([all the ticks you want]))
in order to add the ticks in the graph. Here's the final result:
# Cumulative Distribuition
pdf("g1_3.pdf")
plot(x = f$V2, y = cumsum(f$V1), log = "x", pch = 3,
xlab = "Frequency", ylab = "P(X <= x)", axes = FALSE)
ticks = c(1, 5, 10, 40, 150, 500, 1000)
axis(side = 1, at = ticks)
axis(side = 2)
abline(h = seq(0, 1, 0.2), v = ticks, col = "lightgray", lty = 3)
box()