Sanjay
Sanjay

Reputation: 1236

X- axis labels are not properly aligned in R barplot

I have data.table data to create a stacked chart and with grouping using below code:

causesDf <- causesDf[, c('Type', 'Gender', 'Total')]
causesSort <- causesDf[, lapply(.SD, sum), 
                       by=list(causesDf$Type, causesDf$Gender)]

and Data will be like below:

                           causesDf causesDf.1  Total

 1:                        Illness (Aids/STD)     Female   2892
 2:                 Change in Economic Status     Female   4235
 3:   Cancellation/Non-Settlement of Marriage     Female   6126       
 4:                           Family Problems     Female 133181
 5:                        Illness (Aids/STD)       Male   5831
 6:                 Change in Economic Status       Male  31175
 7:    Cancellation/Non-Settlement of Marriage       Male   5170

and so on..

I am trying to make barplot like below:

barpos <- barplot(sort(causesSort$Total, decreasing=TRUE),
                  col=c("red","green"), xlab="", ylab="", 
                  horiz=FALSE, las=2)

legend("topright", c("Male","Female"), fill=c("red","green"))

end_point <- 0.2 + nrow(causesSort) + nrow(causesSort) - 0.1

text(seq(0.1, end_point, by=1), par("usr")[3] - 30,
     srt=60, adj= 1, xpd=TRUE,
     labels=paste(causesSort$causesDf), cex=0.65)

but X-labels are not aligning properly, did I miss anything?

enter image description here

Expected output like:

enter image description here

Edited:

causesSort

structure(list(causesDf = c("Illness (Aids/STD)", "Change in Economic Status", 
"Cancellation/Non-Settlement of Marriage", "Physical Abuse (Rape/Incest Etc.)", 
"Dowry Dispute", "Family Problems", "Ideological Causes/Hero Worshipping", 
"Other Prolonged Illness", "Property Dispute", "Fall in Social Reputation", 
"Illegitimate Pregnancy", "Failure in Examination", "Insanity/Mental Illness", 
"Love Affairs", "Professional/Career Problem", "Divorce", "Drug Abuse/Addiction", 
"Not having Children(Barrenness/Impotency", "Causes Not known", 
"Unemployment", "Poverty", "Death of Dear Person", "Cancer", 
"Suspected/Illicit Relation", "Paralysis", "Property Dispute", 
"Unemployment", "Poverty", "Family Problems", "Illness (Aids/STD)", 
"Drug Abuse/Addiction", "Other Prolonged Illness", "Death of Dear Person", 
"Causes Not known", "Cancer", "Not having Children(Barrenness/Impotency", 
"Cancellation/Non-Settlement of Marriage", "Paralysis", "Physical Abuse (Rape/Incest Etc.)", 
"Professional/Career Problem", "Love Affairs", "Fall in Social Reputation", 
"Dowry Dispute", "Ideological Causes/Hero Worshipping", "Illegitimate Pregnancy", 
"Failure in Examination", "Change in Economic Status", "Insanity/Mental Illness", 
"Divorce", "Suspected/Illicit Relation", "Not having Children (Barrenness/Impotency", 
"Not having Children (Barrenness/Impotency"), causesDf.1 = c("Female", 
"Female", "Female", "Female", "Female", "Female", "Female", "Female", 
"Female", "Female", "Female", "Female", "Female", "Female", "Female", 
"Female", "Female", "Female", "Female", "Female", "Female", "Female", 
"Female", "Female", "Female", "Male", "Male", "Male", "Male", 
"Male", "Male", "Male", "Male", "Male", "Male", "Male", "Male", 
"Male", "Male", "Male", "Male", "Male", "Male", "Male", "Male", 
"Male", "Male", "Male", "Male", "Male", "Female", "Male"), Total = c(2892, 
4235, 6126, 2662, 31206, 133181, 776, 69072, 4601, 4697, 2391, 
12054, 33352, 21339, 1596, 2535, 1205, 5523, 148134, 3748, 7905, 
4707, 2878, 8093, 2284, 14051, 23617, 24779, 208771, 5831, 28841, 
125493, 5614, 304985, 6180, 2299, 5170, 5002, 1330, 10958, 23700, 
8767, 764, 1342, 103, 14951, 31175, 60877, 1598, 6818, 544, 222
)), row.names = c(NA, -52L), class = c("data.table", "data.frame"
)
# , .internal.selfref = <pointer: 0x00000000098d1ef0>  # seems not to work
)

Upvotes: 3

Views: 2637

Answers (2)

Dave2e
Dave2e

Reputation: 24079

Here is ggplot2 solution. This may provide better control over the final output

library(dplyr)
library(ggplot2)

#Rename columns names
names(causesDf) <- c('Type', 'Gender', 'Total')

#sort male before females
causesDf$Gender<-factor(causesDf$Gender, levels=c("Male", "Female"), ordered=TRUE)

#sort types by total sum and sort in decreasing order
sorted<-causesDf %>% group_by(Type) %>% summarize(gtotal=sum(Total)) %>% arrange(desc(gtotal))
causesDf$Type<-factor(causesDf$Type, levels=sorted$Type, ordered=TRUE)


#plot graph
g<-ggplot(causesDf, aes(x=Type, y=Total, group=Gender, fill=Gender)) + 
  geom_col(position = "dodge") +
  theme(axis.text.x = element_text(angle = 45, hjust=1)) +
  scale_fill_manual(values = alpha(c("blue", "green"), .5))
print(g)

enter image description here

Upvotes: 1

jay.sf
jay.sf

Reputation: 72828

If you don't rely on 45° rotation (that one is a bit more tricky) you could use this solution.

First we need to reshape the data by sex.

library(reshape2)
df2 <- dcast(causesSort, ... ~ causesDf.1 , value.var="Total")

Then we generate rownames from the type column and delete this column.

rownames(df2) <- df2[, 1]
df2 <- df2[, -1]

Then we order the data by one column, e.g. by Female.

df2 <- df2[order(-df2$Female), ]

The labels are the rownames.

# labs <- rownames(df2) 

However, since they are very long (and bad for the reader's eye!), we may have to think of shorter ones. A workaround is to shorten them a little.

labs <- substr(sapply(strsplit(rownames(df2), " "), 
                      function(x) x[1]), 1, 8)

Now we are able to apply barplot().

pos <- barplot(t(df2), beside=TRUE, xaxt="n",
               col=c("#3C6688", "#45A778"), border="white")

pos gives us a matrix of bar positions, because we have a grouped plot we need the column means. We can use it to plot the axis.

axis(1, colMeans(pos), labs, las=2)

Result enter image description here

Upvotes: 3

Related Questions