4

I am trying to create a pie chart with my following data in R:

    2009    2010
US  10  12
UK  13  14
Germany 18  11
China   9   8
Malaysia    7   15
Others  13  15

The command I am using is:

slices<-c(10,13,18,9,7,13,12,14,11,8,15,15)
 lbls <- c("US","UK","Germany","China", "Malaysia", "Others","US","UK","Germany","China", "Malaysia", "Others") 
 pct <- round(slices/sum(slices)*100)
 lbls <- paste(lbls,"%",sep="")
 lbls <- paste(lbls, pct)
 pie(slices,labels = lbls, col=rainbow(length(lbls)),  main="Pie Chart of Countries")

The figure that I am getting is

Now how can I configure the graph so that the countries have same colour scheme? and they follow the same order in two halves, like first it should be US and the UK and so on.

Two simplify the question I want to make two piecharts in one piechart, where one half of piechart represents 2009 and the other half 2010.

kindly help.

Thank you

Jaap
  • 81,064
  • 34
  • 182
  • 193
Angelo
  • 4,829
  • 7
  • 35
  • 56

4 Answers4

12
 lbls0 <- c("US","UK","Germany","China", "Malaysia", "Others","US","UK","Germany","China", "Malaysia", "Others") 
 pct <- round(slices/sum(slices)*100)
 lbls <- paste(lbls,"%",sep="")
 lbls <- paste(lbls, pct)
 pie(slices,labels = lbls, col=rainbow(length(lbls)),
      main="Pie Chart of Countries")


 nlbl <- length(lbls)
 yrs <- rep(2009:2010,each=nlbl/2)
 xlbls <- sprintf("%s (%d) %d%%",lbls0,yrs,pct)
 pie(slices,labels = xlbls, col=rep(rainbow(nlbl/2),2),
      main="Pie Chart of Countries")

Would you be willing to consider a form of visualization that makes it easier to make quantitative comparisons?

 library(ggplot2); theme_set(theme_bw())
 dd <- data.frame(lbls0,yrs,slices,pct)
 dd$lbls0 <- reorder(dd$lbls0,-dd$slices)
 ggplot(dd,aes(x=lbls0,y=slices,fill=lbls0))+
    geom_bar(aes(alpha=factor(yrs)),
                    stat="identity",position=position_dodge(width=1))+
    scale_alpha_discrete(range=c(0.7,1.0))+
    geom_text(aes(label=paste0(pct,"%"),
              group=interaction(lbls0,yrs)),hjust=-0.2,
              position=position_dodge(width=1))+
                  coord_flip()+
    expand_limits(y=20)+labs(x="",y="total")

enter image description here

If you're more interested in comparisons among countries within years rather than among years within countries, you could skip the scale_alpha stuff and use facet_wrap(~yrs) ...

Ben Bolker
  • 211,554
  • 25
  • 370
  • 453
  • Hi Ben, Thank's for the answer, as I am looking something in piecharts I won't be using bar charts. But your pie graphs are also great (+1). Thank you :) – Angelo Jun 01 '14 at 20:49
  • 4
    I'd encourage you to read up on the [great pie chart debate](http://vizthinker.com/grudge-match-pie-chart-vs-bar-chart/) and form your own conclusions ... – Ben Bolker Jun 01 '14 at 20:52
  • +1 for answering the OP's question; +Awesomeness for leading them toward a better choice. – Tyler Rinker Jun 01 '14 at 21:08
  • @BenBolker About the usefulness of pie-charts: this is also recognized in the help pages of R (see my answer for the quote). – Jaap Jun 02 '14 at 07:37
  • 1
    yes, but there are arguments in both directions -- the Cleveland 1985 paper is far from the last word on the topic ... – Ben Bolker Jun 02 '14 at 11:32
8

You can solve this with the help of the reshape2 package:

# reading the data
df <- read.table(header=TRUE, text="Country   2009    2010
US  10  12
UK  13  14
Germany 18  11
China   9   8
Malaysia    7   15
Others  13  15")

# setting the column names correct
colnames(df) <- c("Country","2009","2010")

# reshaping the dataframe
require(reshape2)
df2 <- melt(df, id="Country")

# creating the plot
pie(df2$value, labels=paste0(df2$Country," (",df2$variable,") ",df2$value,"%"),
    col=rainbow(length(levels(df2$Country))), main="Pie Chart of Countries")

which gives: enter image description here


For a variation on the year-labels, you can also use:

pie(df2$value, labels=paste0(df2$Country," ",df2$value,"%"),
    col=rainbow(length(levels(df2$Country))), main="Pie Chart of Countries")
mtext("2009",side=3)
mtext("2010",side=1)

which gives: enter image description here


As @BenBolker said, pie-charts are not a very good way of presenting data. It's worth quoting the help page ?pie were this is recognized as well:

Pie charts are a very bad way of displaying information. The eye is good at judging linear measures and bad at judging relative areas. A bar chart or dot chart is a preferable way of displaying this type of data.

Cleveland (1985), page 264: “Data that can be shown by pie charts always can be shown by a dot chart. This means that judgements of position along a common scale can be made instead of the less accurate angle judgements.” This statement is based on the empirical investigations of Cleveland and McGill as well as investigations by perceptual psychologists.

Community
  • 1
  • 1
Jaap
  • 81,064
  • 34
  • 182
  • 193
4

This might work. At least the two halves have the same color scheme. I am not sure what you mean by the same order.

slices<-c(10,13,18,9,7,13,12,14,11,8,15,15)
pct   <- round(slices/sum(slices)*100)

lbls <- c("US","UK","Germany","China", "Malaysia", "Others","US","UK","Germany","China", "Malaysia", "Others") 
lbls <- paste(lbls,"%",sep="")
lbls <- paste(lbls, pct)

col  <- c("yellow", "orange", "red", "purple", "blue", "green", "yellow", "orange", "red", "purple", "blue", "green")

pie(slices,labels = lbls,  main="Pie Chart of Countries", col = col)

You can shorten the col code with

col  <- rep(c("yellow", "orange", "red", "purple", "blue", "green"),2)

I am not certain what you want regarding the two halves. If you want to standardize the percentages to 50% for each half this might work:

a <- c(7, 9, 12, 6, 5, 9)
a2 <- (a/sum(a)) * 50
a2
# [1]  7.291667  9.375000 12.500000  6.250000  5.208333  9.375000

b <- c(8, 10, 8, 6, 10, 10)
b2 <- (b/sum(b)) * 50
b2
# [1] 7.692308 9.615385 7.692308 5.769231 9.615385 9.615385

pct <- round(c(a2,b2),2)
pct
Mark Miller
  • 12,483
  • 23
  • 78
  • 132
  • Hi, Yes, it does solves the problem of color scheme. But, how can I evenly divide the area into two half circles (or half pies) where one half has the representation of data in 2009 and the second half represents data of 2010. – Angelo Jun 01 '14 at 20:28
  • 1
    Thank you for the check mark, but consider using @BenBolker's answer too. – Mark Miller Jun 01 '14 at 20:46
  • @MarkMiller seen my answer? I'm curious what think of that approach – Jaap Jun 01 '14 at 20:56
  • 1
    @Jaap I like it. It looks nice. I really like the labels, and your color assignment statement is clever and succinct. I copied your code and Ben's and put it in my code library for future reference. – Mark Miller Jun 01 '14 at 21:03
  • @MarkMiller Last one how can I make legend of labels instead of labeling them in figure itself – Angelo Jun 02 '14 at 10:42
3

Here is another solution which was similar to my answer here

slices <- c(10,13,18,9,7,13,12,14,11,8,15,15)
lbls <- c("US","UK","Germany","China", "Malaysia", "Others","US","UK","Germany","China", "Malaysia", "Others") 
pct  <- round(slices/sum(slices)*100)
lbls <- paste(lbls,"%",sep="")
lbls <- paste(lbls, pct)


dat <- data.frame(year = rep(c(2009, 2010), each = 6), lbls, slices)
dat$total <- with(dat, ave(slices, year, FUN = sum))


plot.new()

par(new = TRUE)
pie(dat$slices, border = NA, radius = 1,
    col = rainbow(length(lbls) / 2), labels = lbls,
    main = 'Pie Chart of Countries')

par(new = TRUE)
c2 <- c('grey50', 'grey75')[factor(dat$year)]
pie(dat$slices, border = c2, radius = .7, col = c2, labels = NA)

text(0, c(.3, -.3), 2009:2010)

enter image description here

rawr
  • 20,481
  • 4
  • 44
  • 78