Related
I have a 2 x 2 figure where the columns represent two different variables and the rows represent two different locations. How can I add the names of the two locations to the two rows?
Example Data
library(biwavelet)
par(mfrow = c(2,2),
oma = c(3,3,0,0) + 0.1,
mar = c(1,1,1,1) + 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 = 0.1, col.axis = 'NA')
title("Variable 1", line = 0.1, cex.main = 1.5)
# top-right figure
dat[2] <- sin(dat[1]*.5)
plot(wt(dat),
xaxt = 'n',
col.axis = 'NA',
xlab = "",
ylab = "")
axis(1, at = seq(0, 500, by = 100), cex.axis = 0.1, col.axis = 'NA')
title("Variable 2", line = 0.1, cex.main = 1.5)
# bottom-left figure
dat[2] <- sin(dat[1]*.25)
plot(wt(dat),
cex.axis = 1.5)
# bottom-right figure
dat[2] <- sin(dat[1]*.125)
plot(wt(dat),
col.axis = 'NA',
ylab = "",
xlab = "")
axis(1, at = seq(0, 500, by = 100), cex.axis = 1.5)
title(xlab = "Time (hours)",
ylab = "Period",
outer = TRUE,
line = 1.5,
cex.lab = 1.5)
The ideal figure would look like this
Neither of the suggested solutions so far have put the right-hand labels in the orientation requested. You cannot do so with mtext, but rather need to use text, first allowing text to display outside the plot region with par(xpd=NA). (See ?text and ?par, where one reads that the srt,rotation, parameter only applies to text):
par(mfrow=c(2,2), xpd=FALSE)
par(mar = c(1,1,1,1) + 2)
plot(disp ~ mpg, data = mtcars)
mtext("disp 1", side=3)
plot(I(2*disp) ~ mpg, data = mtcars)
mtext("disp 2", side=3); par(xpd=NA)
text("mpg 1", x=36, y=500, srt=270)
plot(disp ~ I(2*mpg), data = mtcars); par(xpd=NA)
plot(I(2*disp) ~ I(2*mpg), data = mtcars)
text("mpg 2", x=72, y=500, srt=270)
It is not as automatic as mtext in the sense that one needs to look at each plotting figure separately to derive a estimate for the x and y positions in the plotting coordinates.
Here's one method:
par(mfrow=c(2,2))
par(mar = c(1,1,1,1) + 0.1)
plot(disp ~ mpg, data = mtcars)
mtext("disp 1", side=3)
plot(I(2*disp) ~ mpg, data = mtcars)
mtext("disp 2", side=3)
mtext("mpg 1", side=4)
plot(disp ~ I(2*mpg), data = mtcars)
plot(I(2*disp) ~ I(2*mpg), data = mtcars)
mtext("mpg 2", side=4)
Unfortunately, mtext does not support rotating text, so you're stuck with the right labels being oriented as they are.
In case anyone stumbles across this page, the code I ended up using was based on #IRTFM answer, see below. It was challenging finding the appropriate y = in the text() function. I used an iterative approach and found the y = to be much lower than I anticipated.
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)
I am trying to use two different Y axis with the same X Axis and when I set both axes to false the Year wont show up
library(lubridate)
x <- dataset$Date
y <- dataset$AvgCostPerKwh
z <- dataset$ActualkWhSold
par(mar=c(5, 4, 4, 6) + 0.1)
plot(year(x),y, pch = 16, axes = FALSE, ylim = c(0.030,0.090), xlab = "", ylab = "",
type = "b", col="black", main = "Wholesale Power cost")
axis(2, ylim =(range(c(y))), col = "black", las =1)
mtext("$ per KWh", side = 2, line = 2.5)
box()
par(new = TRUE)
plot(year(x),z, pch = 15, xlab = "", ylab = "",ylim=c(5000000,45000000),
axes = FALSE, type="b", col="red")
mtext("Kwh's Sold", side=4, col="red", line=4)
axis(4, ylim=(range(c(z))), col = "red", las=1)
mtext("Year", side = 1, col="black",line=2.5)
legend("topleft", legend = c("AvgCostPerKwh", "ActualKwhSold"),
text.col = c("black", "red"),
pch=c(15,15),col=c("black", "red"))
Image 1
When I set one of the plots to true, I get overlapping values one one side, but the year on the bottom shows up.
library(lubridate)
x <- dataset$Date
y <- dataset$AvgCostPerKwh
z <- dataset$ActualkWhSold
par(mar=c(5, 4, 4, 6) + 0.1)
plot(year(x),y, pch = 16, axes = TRUE, ylim = c(0.030,0.090), xlab = "", ylab = "",
type = "b", col="black", main = "Wholesale Power cost")
axis(2, ylim =(range(c(y))), col = "black", las =1)
mtext("$ per KWh", side = 2, line = 2.5)
box()
par(new = TRUE)
plot(year(x),z, pch = 15, xlab = "", ylab = "",ylim=c(5000000,45000000),
axes = FALSE, type="b", col="red")
mtext("Kwh's Sold", side=4, col="red", line=4)
axis(4, ylim=(range(c(z))), col = "red", las=1)
mtext("Year", side = 1, col="black",line=2.5)
legend("topleft", legend = c("AvgCostPerKwh", "ActualKwhSold"),
text.col = c("black", "red"),
pch=c(15,15),col=c("black", "red"))
image 2
I am not sure, I have followed other examples on here about 2 Y axis and I can't get mine to work.
I have answered my own question for anyone interested, I forgot to add
year(as.Date(dataset$Date, format = "%m/%d/%Y"),"%Y")
at the top before adding
plot(year(x), y, pch=16, axes=FALSE, ylim=c(0.030,1), xlab="", ylab="",
type="b",col="black", main="Wholesale Power Cost")
i am writing up a function to generate a stratified histogram.
Here is my code.
i would like to remove the inside border (so those stack counts are separated by colour only, not colour and border). any ideas?
data("iris")
strathist = function(x, y, ylab = "Frequency", xlab = "", main = ""){
cols = hcl(h=seq(0, 300, by = 50), fixup = FALSE)
h = hist(x, breaks = 20, plot = F)
tb = table(y, cut(x, h$breaks))
par(mar = rep(4, 4))
plot.new()
barplot(tb, space = 0, ylim = c(-0.4, 2 + max(h$count)), col = cols,
ylab = ylab, xlab = xlab, main = main, axisnames = F)
axis(1, 0:(length(h$breaks)-1), h$breaks)
box()
legend("topright", c(rownames(tb)), cex = 0.8, fill = cols)
}
with(iris, strathist(Sepal.Length, Species, xlab = "Sepal.Length", main = "Stratified Histogram of Iris Species"))
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)
For a customer I'm trying to do a combined barplot and lineplot (with points) with two y axis.
Problem: My bars and points are not aligned.
Background: We have several machines and are measuring their number of on/of switches and the amount of time that each machine is running. We want both information together in one plot to save space, because we have several machines.
The data is aggregated by day or hour. Here's some sample data:
date <- seq(as.Date("2016-10-01"), as.Date("2016-10-10"), "day")
counts <- c(390, 377, 444, NA, NA, NA, NA, 162, 166, 145)
runtime <- c(56.8, 59.4, 51.0, NA, NA, NA, NA, 38.5, 40.9, 43.4)
df <- data.frame(date = date, counts = counts, runtime = runtime)
Here's what I tried so far:
par(mar = c(3,4,4,4) + 0.3)
barplot(df$runtime, col = "palegreen2", border = "NA", ylab = "runtime in [%]",
ylim = c(0,100), font.lab = 2)
par(new = TRUE)
ymax <- max(df$counts, na.rm = TRUE) * 1.05
plot(df$date, df$counts, type = "n", xlab = "", ylab = "", yaxt = "n",
main = "Machine 1", ylim = c(0, ymax))
abline(v = date, col = "red", lwd = 2.5)
lines(df$date, df$counts, col = "blue", lwd = 2)
points(df$date, df$counts, pch = 19, cex = 1.5)
axis(4)
mtext("Number of switching operations", side = 4, line = 3, font = 2)
I found some inspiration for two axis here: http://robjhyndman.com/hyndsight/r-graph-with-two-y-axes/
What can I do to get bars with their middle aligned with the points of the lineplot?
The problem you are running into is the call to the second plot function after the barplot. This is shifting/resizing the plotting canvas which is causing the shift in the subsequent points.
Here is a quick work-around that just rescales the points and lines onto the barplot. It saves the barplot as an object, which stores x-axis locations for the mid-points of the bars. Then, when you plot the abline, lines and points using 'bp' as the x-axis variable, they will be correctly aligned.
ymax <- max(df$counts, na.rm = TRUE) * 1.05
par(mar=c(4.1,5.1,2.1,5.1))
bp <- barplot(df$runtime, col = "palegreen2", border = "NA", ylab = "runtime in [%]",
ylim = c(0,100), font.lab = 2, xlim=c(0.2,12), )
barplot(df$runtime, col = "palegreen2", ylab = "runtime in [%]", border="NA",
ylim = c(0,100), font.lab = 2)
abline(v = bp, col = "red", lwd = 2.5)
lines(bp, df$counts/ymax*100, col = "blue", lwd = 2)
points(bp, df$counts/ymax*100, pch = 19, cex = 1.5)
axis(4,at=c(0,20,40,60,80,100), labels=c("0","100","200","300","400","500"))
mtext("Number of switching operations", side = 4, line = 3, font = 2)
axis(1, at=bp, labels=df$date)
#emilliman: Thank you for your patience and input! Your plot is not completely correct, because the scaling of the second y-axis does not fit the points' values, but your idea helped me to find a solution!
Here's my new code:
library(plyr)
ymax <- max(df$counts, na.rm = TRUE)
ymax_up <- round_any(ymax, 100, f = ceiling)
ylab <- ymax_up/5 * c(0:5)
par(mar = c(3,4,4,4) + 0.3)
bp <- barplot(df$runtime, col = "palegreen2", border = "NA", ylab = "runtime in [%]",
ylim = c(0,100), font.lab = 2, main = "Machine 1")
abline(v = bp, col = "red", lwd = 2.5)
lines(bp, 100/ymax_up * df$counts, col = "blue", lwd = 2)
points(bp, 100/ymax_up * df$counts, pch = 19, cex = 1.5)
axis(4,at=c(0,20,40,60,80,100), labels= as.character(ylab))
mtext("Number of switching operations", side = 4, line = 3, font = 2)
xlab <- as.character(df$date, format = "%b %d")
axis(1, at=bp, labels = xlab)
abline(h = c(0,100))
(http://i.imgur.com/9YtYGSD.png)
Maybe this is helpful for others who run into this problem.