简体   繁体   中英

Side-by-side barplot with line plot overlay in R

Ok, I have data in a dataframe, would like to take two variables y1 and y2 and create a side-by-side barplot comparison in which bar height is equal to the value of each element in y1 and y2. Then I want to superimpose a line with the ratio of the two variables, with a second y-axis for these values. My specific problem is that I cannot scale the second y axis appropriately (so in my example reduced the ratio so that it would fall in graph).

More generally, I have a poor understanding of how barcharts work in base graphics and feel like I had to hack my way through it - in spite of reading the multiple posts on this, and a number of tutorials which mostly don't go into enough detail. Some things I am not clear about; A. What is the best way to go from data in a df to data suitable for a barchart - do the data have to be transposed into a barchart matrix as I do here, and why? B. What determines the x-axis placement of the bars (ie what is the "myplot" object and how do the values get determined? Is there a way to set x locations of my points/lines more elegantly? I had to force it using somewhat ugly coding because I don't really understand how it works. C. Not sure about how I would go from row names in my df if I had any, to category (x-axis) names in my bar chart. I sort of had to force this in my plot parameters. D. Is there a definitive discussion about barcharts somewhere that goes into depth a bit more on the inner workings of the bar chart?

rm(list = ls(all = TRUE))
df <- data.frame(y1 = runif(10, min=0, max=1), y2 = runif(10, min=1, max=2))
df$ratio <- df$y2/df$y1
df

barmatrix <- t(df[,1:2])
barmatrix

par(mfrow = c(1,1))
myplot <- barplot(barmatrix, main="My Barchart", ylab = "Values", ylim = c(0,3), cex.lab = 1.5, cex.main = 1.4, beside=TRUE, names.arg=c("0","1","2","3","4","5","6","7","8","9"))
lines(x = myplot[1, ] + 0.5, y = df$ratio/3)
points(x = myplot[1, ] + 0.5, y = df$ratio/3)
axis(4, ylim = c(0, 20))

you can scale down by 10 to fit on the plot, then scale the numbers (that is, the labels) on your added axis.

par(mfrow = c(1,1))
myplot <- barplot(barmatrix, main="My Barchart", ylab = "Values", ylim = c(0,3), cex.lab = 1.5, cex.main = 1.4, beside=TRUE, names.arg=c("0","1","2","3","4","5","6","7","8","9"))
lines(x = myplot[1, ] + 0.5, y = df$ratio/10)
points(x = myplot[1, ] + 0.5, y = df$ratio/10)
axis(4, at=0:6/2,labels=0:6*5)

Update: to dynamically scale

rm(list = ls(all = TRUE))
df <- data.frame(y1 = runif(10, min=0, max=1), y2 = runif(10, min=1, max=2))
df$ratio <- df$y2/df$y1
df

barmatrix <- t(df[,1:2])
barmatrix

sf <- max(pretty(df$ratio/3)) # scale factor
# divide by 3 since that is your limit on the barplot ylim
sf

par(mfrow = c(1,1))
myplot <- barplot(barmatrix, main="My Barchart", ylab = "Values", ylim = c(0,3), cex.lab = 1.5, cex.main = 1.4, beside=TRUE, names.arg=c("0","1","2","3","4","5","6","7","8","9"))
lines(x = myplot[1, ] + 0.5, y = df$ratio/sf)
points(x = myplot[1, ] + 0.5, y = df$ratio/sf)
axis(4, at=0:3,labels=0:3*sf)

Update 2: To answer more of your question. Each row of your matrix myplot has the x positions for each series. You can find the average for each column to more flexibly find the midpoint for multiple series.

You can also label with the row.names directly.

And with type="o" you can plot lines and points at one go.

rm(list = ls(all = TRUE))
df <- data.frame(y1 = runif(10, min=0, max=1), y2 = runif(10, min=1, max=2))
df$ratio <- df$y2/df$y1

row.names(df) <- LETTERS[1:10]
df
barmatrix <- t(df[,1:2])
barmatrix

sf <- max(pretty(df$ratio/3)) # scale factor
# divide by 3 since that is your limit on the barplot ylim
sf

par(mfrow = c(1,1))
myplot <- barplot(barmatrix, main="My Barchart", ylab = "Values", ylim = c(0,3),
   cex.lab = 1.5, cex.main = 1.4, beside=TRUE, names.arg=row.names(df))
lines(x = colSums(myplot)/nrow(myplot), y = df$ratio/sf,type="o")

axis(4, at=0:3,labels=0:3*sf)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM