Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a horizontal bar plots in the reverse direction

I'm trying to do a pyramid-"like" plot in R and I think I am close. I know there are functions such as plotrix's pyramid.plot but what I want to do isn't a real pyramid plot. In a pyramid plot, there are text labels down the middle that line up with the bars on the left and on the right. Instead, what I'd like to do is have two columns of text with bars coming away from them.

I'm using ggplot (but I guess I don't have to) and the multiplot function. A minimal example would be something like this:

mtcars$`car name` <- rownames(mtcars)
obj_a <- ggplot (mtcars, aes (x=`car name`, y=mpg))
obj_a <- obj_a + geom_bar (position = position_dodge(), stat="identity")
obj_a <- obj_a + coord_flip () 
obj_a <- obj_a + xlab ("")

USArrests$`states` <- rownames(USArrests)
obj_b <- ggplot (USArrests, aes (x=`states`, y=UrbanPop))
obj_b <- obj_b + geom_bar (position = position_dodge(), stat="identity")
obj_b <- obj_b + coord_flip () 
obj_b <- obj_b + xlab ("")

multiplot (obj_a, obj_b, cols=2)

Which looks like this:

Example graph

I guess what I'd like is just to flip the left half so that each row has (from left-to-right): left bar, car model, state name, right bar. (The graph I'm making will have the same number of rows in both halves so it won't look so cramped.) However, the point is, there are two columns of text, not one.

Of course, since both halves are independent of each other, my real problem is I don't know how to make the left half. (A bar plot with bars going in the opposite direction.) But I thought I'd also explain what I'm trying to do...

Thank you in advance!

like image 394
Ray Avatar asked Sep 21 '17 10:09

Ray


2 Answers

You can set the mpg values in obj_a negative, & position the car names axis on the opposite side:

ggplot (mtcars, aes (x=`car name`, y=-mpg)) +         # y takes on negative values
  geom_bar (position = position_dodge(), stat = "identity") + 
  coord_flip () + 
  scale_x_discrete(name = "", position = "top") +     # x axis (before coord_flip) on opposite side
  scale_y_continuous(name = "mpg",
                     breaks = seq(0, -30, by = -10),  # y axis values (before coord_flip) 
                     labels = seq(0,  30, by =  10))  # show non-negative values

obj_a

like image 146
Z.Lin Avatar answered Sep 30 '22 11:09

Z.Lin


It seems that pyramid.plot already does what you need. Using their example:

xy.pop<-c(3.2,3.5,3.6,3.6,3.5,3.5,3.9,3.7,3.9,3.5,3.2,2.8,2.2,1.8,
          1.5,1.3,0.7,0.4)
xx.pop<-c(3.2,3.4,3.5,3.5,3.5,3.7,4,3.8,3.9,3.6,3.2,2.5,2,1.7,1.5,
          1.3,1,0.8)
agelabels<-c("0-4","5-9","10-14","15-19","20-24","25-29","30-34",
             "35-39","40-44","45-49","50-54","55-59","60-64","65-69","70-74",
             "75-79","80-44","85+")
mcol<-color.gradient(c(0,0,0.5,1),c(0,0,0.5,1),c(1,1,0.5,1),18)
fcol<-color.gradient(c(1,1,0.5,1),c(0.5,0.5,0.5,1),c(0.5,0.5,0.5,1),18)
par(mar=pyramid.plot(xy.pop,xx.pop,labels=agelabels,
                     main="Australian population pyramid 2002",lxcol=mcol,rxcol=fcol,
                     gap=0.5,show.values=TRUE))
# three column matrices
avtemp<-c(seq(11,2,by=-1),rep(2:6,each=2),seq(11,2,by=-1))
malecook<-matrix(avtemp+sample(-2:2,30,TRUE),ncol=3)
femalecook<-matrix(avtemp+sample(-2:2,30,TRUE),ncol=3)



# *** Make agegrps a two column data frame with the labels ***

# group by age 
agegrps<-data.frame(c("0","11","21","31","41","51",
           "61-70","71-80","81-90","91+"),
           c("10","20","30","40","50","60",
             "70","80","90","91"))


oldmar<-pyramid.plot(malecook,femalecook,labels=agegrps,
                     unit="Bowls per month",lxcol=c("#ff0000","#eeee88","#0000ff"),
                     rxcol=c("#ff0000","#eeee88","#0000ff"),laxlab=c(0,10,20,30),
                     raxlab=c(0,10,20,30),top.labels=c("Males","Age","Females"),gap=4,
                     do.first="plot_bg(\"#eedd55\")")
# put a box around it
box()
# give it a title
mtext("Porridge temperature by age and sex of bear",3,2,cex=1.5)
# stick in a legend
legend(par("usr")[1],11,c("Too hot","Just right","Too cold"),
       fill=c("#ff0000","#eeee88","#0000ff"))
# don't forget to restore the margins and background
par(mar=oldmar,bg="transparent")

Result: enter image description here

like image 28
R. Schifini Avatar answered Sep 30 '22 11:09

R. Schifini