PMaier
PMaier

Reputation: 654

2-layer barplot in R

I am trying to build a (somewhat) complex barplot in R. The idea is to overlay two charts, whereby the bars in one are wider than in the other one, such that both bars are always visible.

Here's what I have right now:

# GENERATE THE DATA  
Age = c(50, 55, 60, 65, 70)                                     # Age groups  
Male = c(15.4, 24.3, 37.0, 54.6, 71.1)                          # Death rates for males  
Female = c(8.4, 13.6, 19.3, 35.1, 50.0)                         # Death rates for females  
Deathrate = matrix(c(Male,Female), nrow=length(Age), ncol=2, dimnames=list(Age, c("Male","Female")))         

# GENERATE THE DATA  
barplot(Deathrate[,1], col="red")
par(new=TRUE)
barplot(Deathrate[,2], space=1, col="blue")

Now, as you can see, the two plots are shown, but while both middle bars are nicely overlapping and centered, all other bars are not centered. For example, the rightmost blue bar is shown on the edge of the rightmost red bar.

Does anyone have a simple solution to center all bars?

Thanks, Philipp

PS I know that the chart isn't pretty (overlapping legends etc.)....

Upvotes: 1

Views: 3021

Answers (4)

akond
akond

Reputation: 16035

 barplot(as.vector(rbind(Male, Female)),col=c('red','blue'), space=rep_len(1:0,length(Male)*2), beside=T, legend.text=c('Male', 'Female'));

enter image description here

P.S. the bars are not centered, but I think they are prettier this way.

Upvotes: 1

lawyeR
lawyeR

Reputation: 7664

Here is a solution using ggplot2

Death.df <- as.data.frame(Deathrate) # ggplot2 requires a data frame
Death.df$ages <- rownames(Death.df) # add a column with rownames
Death.m <- melt(Death.df, id.vars = "ages") # melt the dataframe to long form

ggplot(Death.m) +
  geom_histogram(aes(x = ages, y = value), stat = "identity", fill = "red", width = 0.4) +
  geom_histogram(aes(x = ages, y = value), stat = "identity", fill = "blue", width = 0.5, position = "dodge") +
  ggtitle("Death Rates of Males and Females\nMales in Red and Females in Blue")

enter image description here

Upvotes: 2

MrFlick
MrFlick

Reputation: 206243

barplot certainly wasn't optimized for this case. It's not too hard to roll your own plotting function for this type of plot if you want even more control.

cbarplot <- function(x, ..., bcols=c("red","blue"), bwidth=c(.4,.3)) {
    plot(1, type="n", xlim=c(.5,(nrow(x)+.5)), ylim=c(0,max(x)), xaxt="n", ...)
    for(i in 1:ncol(x)) {
        w <- bwidth[i]
        rect(seq_len(nrow(x))-w, 0, seq_len(nrow(x))+w, x[,i], col=bcols[i])
    }
    axis(1, at=1:nrow(x), rownames(x))
}

cbarplot(Deathrate, ylab="Count", xlab="Age")

enter image description here

Upvotes: 1

shadow
shadow

Reputation: 22313

You can use add=TRUE together with apropriate values for width and space.

barplot(Deathrate[,1], col="red")
barplot(Deathrate[,2], width=0.5, space=c(0.9, 1.4, 1.4, 1.4, 1.4), col="blue", add=TRUE)

Upvotes: 3

Related Questions