R: Faceted Bar Chart with Percentages Labels Independent for Each Plot

R: Faceted bar chart with percentages labels independent for each plot

This method for the time being works. However the PANEL variable isn't documented and according to Hadley shouldn't be used.
It seems the "correct" way it to aggregate the data and then plotting, there are many examples of this in SO.

ggplot(df, aes(x = factor_variable, y = (..count..)/ sapply(PANEL, FUN=function(x) sum(count[PANEL == x])))) +
geom_bar(fill = "deepskyblue3", width=.5) +
stat_bin(geom = "text",
aes(label = paste(round((..count..)/ sapply(PANEL, FUN=function(x) sum(count[PANEL == x])) * 100), "%")),
vjust = -1, color = "grey30", size = 6) +
facet_grid(. ~ second_factor_variable)

Sample Image

percentage on y lab in a faceted ggplot barchart?

Try this:

# first make a dataframe with frequencies
df <- as.data.frame(with(test, table(test1,test2)))
# or with count() from plyr package as Hadley suggested
df <- count(test, vars=c('test1', 'test2'))
# next: compute percentages per group
df <- ddply(df, .(test1), transform, p = Freq/sum(Freq))
# and plot
ggplot(df, aes(test2, p))+geom_bar()+facet_grid(~test1)

alt text

You could also add + scale_y_continuous(formatter = "percent") to the plot for ggplot2 version 0.8.9, or + scale_y_continuous(labels = percent_format()) for version 0.9.0.

How to add percentage or count labels above percentage bar plot?

Staying within ggplot, you might try

ggplot(test, aes(x= test2,  group=test1)) + 
geom_bar(aes(y = ..density.., fill = factor(..x..))) +
geom_text(aes( label = format(100*..density.., digits=2, drop0trailing=TRUE),
y= ..density.. ), stat= "bin", vjust = -.5) +
facet_grid(~test1) +
scale_y_continuous(labels=percent)

For counts, change ..density.. to ..count.. in geom_bar and geom_text

UPDATE for ggplot 2.x

ggplot2 2.0 made many changes to ggplot including one that broke the original version of this code when it changed the default stat function used by geom_bar ggplot 2.0.0. Instead of calling stat_bin, as before, to bin the data, it now calls stat_count to count observations at each location. stat_count returns prop as the proportion of the counts at that location rather than density.

The code below has been modified to work with this new release of ggplot2. I've included two versions, both of which show the height of the bars as a percentage of counts. The first displays the proportion of the count above the bar as a percent while the second shows the count above the bar. I've also added labels for the y axis and legend.

  library(ggplot2)
library(scales)
#
# Displays bar heights as percents with percentages above bars
#
ggplot(test, aes(x= test2, group=test1)) +
geom_bar(aes(y = ..prop.., fill = factor(..x..)), stat="count") +
geom_text(aes( label = scales::percent(..prop..),
y= ..prop.. ), stat= "count", vjust = -.5) +
labs(y = "Percent", fill="test2") +
facet_grid(~test1) +
scale_y_continuous(labels=percent)
#
# Displays bar heights as percents with counts above bars
#
ggplot(test, aes(x= test2, group=test1)) +
geom_bar(aes(y = ..prop.., fill = factor(..x..)), stat="count") +
geom_text(aes(label = ..count.., y= ..prop..), stat= "count", vjust = -.5) +
labs(y = "Percent", fill="test2") +
facet_grid(~test1) +
scale_y_continuous(labels=percent)

The plot from the first version is shown below.

Sample Image

print percentage labels within a facet_grid

Taking a lead from the question you linked:

You also need to pass the new dataframe returned by ddply to the geom_text call together with aesthetics.

library(ggplot2)
library(plyr)

# Reduced the dataset
set.seed(1)
dx <- data.frame(x = sample(letters[1:2], 1000, replace=TRUE),
y = sample(letters[5:6], 1000, replace=TRUE),
z = factor(sample(1:3, 5000, replace=TRUE)))

# Your ddply call
m <- ddply(data.frame(table(dx)), .(x,y), mutate,
pct = round(Freq/sum(Freq) * 100, 0))

# Plot - with a little extra y-axis space for the label
d <- ggplot(dx, aes(z, fill=z)) +
geom_bar() +
scale_y_continuous(limits=c(0, 1.1*max(m$Freq))) +
facet_grid(y~x)

d + geom_text(data=m, aes(x=z, y=Inf, label = paste0(pct, "%")),
vjust = 1.5, size = 5)

Sample Image

(i do think this is a lot of ink just to show N(%), especially if you have lots of facets and levels of z)

ggplot bar chart of percentages over groups

First of all: Your code is not reproducible for me (not even after including library(ggplot2)). I am not sure if ..count.. is a fancy syntax I am not aware of, but in any case it would be nicer if I would have been able to reproduce right away :-).

Having said that, I think what you are looking for it described in http://docs.ggplot2.org/current/geom_bar.html and applied to your example the code

library(ggplot2)
data(mtcars)
mtcars$gear <- as.factor(mtcars$gear)
ggplot(data=mtcars, aes(cyl))+
geom_bar(aes(fill=as.factor(gear)), position="fill")

produces

Sample Image

Is this what you are looking for?


Afterthought: Learning melt() or its alternatives is a must. However, melt() from reshape2 is succeeded for most use-cases by gather() from tidyr package.

Condition a ..count.. summation on the faceting variable

Update geom_bar requires stat = identity.

Sometimes it's easier to obtain summaries outside the call to ggplot.

df <- data.frame(x = c('a', 'a', 'b','b'), f = c('c', 'd','d','d'))

# Load packages
library(ggplot2)
library(plyr)

# Obtain summary. 'Freq' is the count, 'pct' is the percent within each 'f'
m = ddply(data.frame(table(df)), .(f), mutate, pct = round(Freq/sum(Freq) * 100, 1))

# Plot the data using the summary data frame
ggplot(data = m, aes(x = x, y = Freq)) +
geom_bar(stat = "identity", width = .7) +
geom_text(aes(label = paste(m$pct, "%", sep = "")), vjust = -1, size = 3) +
facet_wrap(~ f, ncol = 2) + theme_bw() +
scale_y_continuous(limits = c(0, 1.2*max(m$Freq)))

Sample Image

ggplot2 - facet and separate y axis calculations

I would do something like this. Starting with your d data frame:

dSummarised <- group_by(d, time, weapons) %>% 
summarise(n = n()) %>%
mutate(percent = n / sum(n))
ggplot(dSummarised, aes(x=weapons, y=percent, fill = (weapons))) +
geom_bar(stat = "identity") +
geom_text(aes(label=n), vjust = -1) +
facet_grid(time ~ .) +
coord_cartesian(ylim = c(0, .6))

If for any reason you want different scales on the axis put the parameter scales = "free_y" inside faced_grid but the remove the coor_cartesian part.
Hope this helps.



Related Topics



Leave a reply



Submit