How can I add axis labels to a plot with custom axes? - r

I want to add axes labels to the plot generated by the following code. Specifically, I would want an x-axis label that reads "Fibril Diameter (nm)" and a y-axis label that reads "Density". Any idea how I could accomplish this? Thanks!
den1 = density(CDE1$V1)
den2 = density(CDE1$V2)
col1 = hsv(h = 0.65, s = 0.6, v = 0.8, alpha = 0.5)
col2 = hsv(h = 0.85, s = 0.6, v = 0.8, alpha = 0.5)
op = par(mar = c(3, 3, 2, 2))
plot.new( )
plot.window(xlim = c(25,65), ylim = c(0, 0.14))
axis(side = 1, pos = 0, at = seq(from = 25, to = 65, by = 5), col = "gray20",
lwd.ticks = 0.25, cex.axis = 1, col.axis = "gray20", lwd = 1.5)
axis(side = 2, pos = 25, at = seq(from = 0, to = 0.14, by = 0.02), col = "gray20",
las = 2, lwd.ticks = 0.5, cex.axis = 1, col.axis = "gray20", lwd = 1.5)
polygon(den1$x, den1$y, col = col1, border ="black",lwd = 2)
polygon(den2$x, den2$y, col = col2, border ="black",lwd = 2)
text(52, 0.10, labels ="CDET", col =col1, cex = 1.25,font=2)
text(35, 0.03, labels ="SDFT", col =col2, cex = 1.25,font=2)
par(op)
title(main="Gestational Day 100/283")
Here's a picture of what the code generates so far...
Image

You can add your axis labels using title()
title(main="Gestational Day 100/283",
xlab="Fibril Diameter (nm)",
ylab="Density")
or with mtext() which will make it easier for you to fine-tune their exact positioning:
mtext("Fibril Diameter (nm)", side=1, line=2)
mtext("Density", side=2, line=2)
In either case, you will probably need to increase your bottom and left plot margins so that the labels are actually visible, e.g. like this:
op = par(mar=c(4.5, 4.5, 2, 2))

Related

base R: how to keep axis box in each plot of a 2 x 2 figure

I am making a 4-panel figure where each column represents a different variable and each row represents a different location. When I add the first two plots (i.e., the top row) there is a box surrounding each plot. However, when I add the bottom two figures (i.e., the bottom row) the box around the top row plots disappears. Any idea how to make sure there is a box around each plot?
Example
Make the two figures of the top row first
library(biwavelet)
par(mfrow = c(2,2), xpd=FALSE)
par(mar = c(1,1,1.1,1.1) + 0.1,
oma = c(3,3,0.5,0.5) + 0.1)
dat <- as.data.frame(matrix(nrow = 500, ncol = 2))
dat[1] <- seq(1,500)
dat[2] <- sin(dat[1])
# top-left figure
plot(wt(dat),
xaxt = 'n',
xlab = "",
cex.axis = 1.5,
cex.lab = 1.5)
axis(1, at = seq(0, 500, by = 100), cex.axis = 1.5, col.axis = 'NA')
mtext("Variable 1", side = 3, cex = 1.5, line = 0.1)
box(lty = "solid", col = 'black')
# top-right figure
dat[2] <- sin(dat[1]*.5)
plot(wt(dat),
xaxt = 'n',
col.axis = 'NA',
xlab = "",
ylab = ""); par(xpd = NA)
axis(1, at = seq(100, 500, by = 100), cex.axis = 0.1, col.axis = 'NA')
mtext("Variable 2", side = 3, cex = 1.5, line = 0.1); par(xpd = NA)
text("Location 1", x = 520, y = 4.1, srt = 270, cex = 1.5)
box(lty = "solid", col = 'black')
Now add bottom two plots and watch the black box around the top two plots disappear
# bottom-left figure
dat[2] <- sin(dat[1]*.25)
plot(wt(dat),
cex.axis = 1.5,
xlab = "",
ylab = "")
axis(1, at = seq(100, 500, by = 100), cex.axis = 1.5)
box(lty = "solid", col = 'black')
# bottom-right figure
dat[2] <- sin(dat[1]*.125)
plot(wt(dat),
col.axis = 'NA',
ylab = "",
xlab = "")
axis(1, at = seq(100, 500, by = 100), cex.axis = 1.5); par(xpd = NA)
text("Location 2", x = 520, y = 4.5, srt = 270, cex = 1.5)
box(lty = "solid", col = 'black')
title(xlab = "Time (hours)",
ylab = "Period",
outer = TRUE,
line = 1.5,
cex.lab = 1.5)
I have tried using box(lty = "solid", col = 'black'), which has not worked. I have also tried using fg = 'black' and bty = "o" inside of plot(), which has not worked.
How can I keep the black box around the top two plots?
With par(xpd=NA) before your text() commands you are doing the xpd=NA setting globally, hence influencing all subsequent plotting, and your bottom row graphs are somehow overdrawing the top row ones. Just move the xpd=NA inside your text() functions (e.g. text('Location 1', ..., xpd=NA)) and everything should work as expected:
library(biwavelet)
par(mfrow = c(2,2), xpd=F)
par(mar = c(1,1,1.1,1.1) + 0.1,
oma = c(3,3,0.5,0.5) + 0.1)
dat <- as.data.frame(matrix(nrow = 500, ncol = 2))
dat[1] <- seq(1,500)
dat[2] <- sin(dat[1])
# top-left figure
plot(wt(dat),
xaxt = 'n',
xlab = "",
cex.axis = 1.5,
cex.lab = 1.5)
axis(1, at = seq(0, 500, by = 100), cex.axis = 1.5, col.axis = 'NA')
mtext("Variable 1", side = 3, cex = 1.5, line = 0.1)
box(lty = "solid", col = 'black')
# top-right figure
dat[2] <- sin(dat[1]*.5)
plot(wt(dat),
xaxt = 'n',
col.axis = 'NA',
xlab = "",
ylab = "")
axis(1, at = seq(100, 500, by = 100), cex.axis = 0.1, col.axis = 'NA')
mtext("Variable 2", side = 3, cex = 1.5, line = 0.1)
text("Location 1", x = 520, y = 4.1, srt = 270, cex = 1.5, xpd=NA)
box(lty = "solid", col = 'black')
# bottom-left figure
dat[2] <- sin(dat[1]*.25)
plot(wt(dat),
cex.axis = 1.5,
xlab = "",
ylab = "")
axis(1, at = seq(100, 500, by = 100), cex.axis = 1.5)
box(lty = "solid", col = 'black')
# bottom-right figure
dat[2] <- sin(dat[1]*.125)
plot(wt(dat),
col.axis = 'NA',
ylab = "",
xlab = "")
axis(1, at = seq(100, 500, by = 100), cex.axis = 1.5)
text("Location 2", x = 520, y = 4.5, srt = 270, cex = 1.5, xpd=NA)
box(lty = "solid", col = 'black')
title(xlab = "Time (hours)",
ylab = "Period",
outer = TRUE,
line = 1.5,
cex.lab = 1.5)

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)
)

My layout doesn't allow me to show xlab and ylab

It looks like something simple I am missing but have no idea how to deal with this.
So I used a layout() function and I managed to get the layout as I wanted as below picture. Iris data was used in my coding.
Problem is, it does not show me the x label and y label on the output when I use plot() functions after this. And xaxis and yaxis for plot() looks overlapping. I am not sure how to deal with this problem.
There was no problem for x and y labelling before introducing plot.new() and par() to set up the main name of my diagram. (i.e. before I use the code from plot.new() to title(), xlab and ylab were shown)
I used 6 different plots in my original code, including, the plot.new() for title(), but I omitted the rest of them for convenience
Here is my code below,
x <- iris$Sepal.Length
y <- iris$Species
x_min <- min(iris$Sepal.Length)
x_max <- max(iris$Sepal.Length)
y_min <- min(iris$Sepal.Width)
y_max <- max(iris$Sepal.Width)
layout(matrix(c(1,1,1,1,1,1,
2,2,3,3,4,4,
5,5,5,6,6,6), nc=6, byrow = TRUE), heights=c(lcm(1),1,1,1,1))
layout.show(6)
par("mar"=c(1,1,1,1,1,1))
plot.new()
plot.window(xlim=c(0,1), ylim=c(0,1))
text(x=0.5,y=0.5,"scatter and density plots for Sepal and Length and Sepal Width" ,font=2, cex=1.5)
plot(...)
You can use the xlab and ylab arguments in title. However, the way you have constructed the plot means that when you reset par at the end, these are drawn off the page due ti their position relative to your custom axis. If you simply leave par alone, you get:
den1 = density(CDE1$V1)
den2 = density(CDE1$V2)
col1 = hsv(h = 0.65, s = 0.6, v = 0.8, alpha = 0.5)
col2 = hsv(h = 0.85, s = 0.6, v = 0.8, alpha = 0.5)
plot.new()
plot.window(xlim = c(25,65), ylim = c(0, 0.14))
axis(side = 1, pos = 0, at = seq(from = 25, to = 65, by = 5), col = "gray20",
lwd.ticks = 0.25, cex.axis = 1, col.axis = "gray20", lwd = 1.5)
axis(side = 2, pos = 25, at = seq(from = 0, to = 0.14, by = 0.02),
col = "gray20", las = 2, lwd.ticks = 0.5, cex.axis = 1,
col.axis = "gray20", lwd = 1.5)
polygon(den1$x, den1$y, col = col1, border ="black",lwd = 2)
polygon(den2$x, den2$y, col = col2, border ="black",lwd = 2)
text(52, 0.10, labels ="CDET", col =col1, cex = 1.25,font=2)
text(35, 0.03, labels ="SDFT", col =col2, cex = 1.25,font=2)
title(main = "Gestational Day 100/283",
xlab = "Fibril Diameter (nm)",
ylab = "density")
Of course, you could get a similar plot with less code and much easier adjustments using ggplot:
library(ggplot2)
ggplot(tidyr::pivot_longer(CDE1, 1:2), aes(value, fill = name)) +
geom_density() +
scale_fill_manual(values = c(col1, col2), labels = c("CDET", "SDFT")) +
scale_x_continuous(breaks = seq(25, 65, 5), limits = c(25, 65)) +
scale_y_continuous(breaks = seq(0, 0.14, 0.02), limits = c(0, 0.14)) +
theme_classic(base_size = 16) +
labs(title = "Gestational Day 100/283", x = "Fibril Diameter (nm)",
fill = NULL) +
theme(plot.title = element_text(hjust = 0.5))
Data used
Obviously, we don't have your data, so I had to create a reproducible approximation:
set.seed(123)
CDE1 <- data.frame(V1 = rnorm(20, 47.5, 4), V2 = rnorm(20, 44, 5))

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.

Resources