I have a data frame that looks like this:
category = c(rep("house", 2), rep("apartment", 4), rep("condo", 3))
sample = paste("ID", seq(1:9), sep='')
group = c(rep(1,9), rep(2,9))
value = c(0.990000, 0.608143, 0.451284, 0.500343, 0.482670, 0.358965, 0.393272, 0.300472, 0.334363, 0.001000, 0.391857, 0.548716, 0.499657, 0.517330, 0.641035, 0.606728, 0.699528, 0.665637)
data = as.data.frame(cbind(category, sample, group, value))
I want to use the variable 'category' to facet_wrap a stacked barplot, like this:
ggplot(data, aes(x=sample, y=value, fill=group)) +
geom_bar(stat="identity", width=1) +
facet_wrap(facet ~ ., scales="free_x")
The number of samples in each category is uneven but ggplot automatically makes each barplot the same width, meaning that the bars across plots are not the same width, like this:
Is there a way to force ggplot to keep the bars all the same width, such that the overall width of each barplot is different across plots?
Thanks for any tips!
Try facet_grid
ggplot(data, aes(x = sample, y = value, fill = group)) +
geom_bar(stat = "identity", width = 1, col = "black") +
facet_grid(. ~ category, scales = "free", space = "free")
Related
I'm generating a stacked density plot:
ggplot(data=tydy_rawdata, aes(x=timepoint, y=tpm, group=fct_inorder(names),
fill=fct_inorder(names))) +
geom_density(position="fill",
stat="identity") +
scale_fill_manual(values = rev(mycolors))
plot :
I would like to add label on each curve (or at least the top 3 or 4) basing on the "names" displayed on the right.
I'm trying adding geom_text but the result is this :
gplot(data=tydy_rawdata, aes(x=timepoint, y=tpm, group=fct_inorder(names),
fill=fct_inorder(names))) +
geom_density(position="fill",
stat="identity") +
geom_text(aes(label=names)) +
scale_fill_manual(values = rev(mycolors))
plot :
Are there some way to do it?
First, your chart is a stacked area chart, i.e. geom_density with stat="identity" is equal to geom_area. Second, when adding labels via geom_text you have to take account of the position argument. As you use position="fill" for your density/area chart you also have to do the same for geom_text.
As you provided no example data I created my own to make your issue reproducible:
library(ggplot2)
library(forcats)
set.seed(123)
tydy_rawdata <- data.frame(
names = rep(LETTERS[1:10], each = 6),
timepoint = factor(seq(6)),
tpm = runif(6 * 10, 0, 80)
)
ggplot(data = tydy_rawdata, aes(
x = timepoint, y = tpm,
group = fct_inorder(names), fill = fct_inorder(names)
)) +
geom_area(
position = "fill",
color = "black"
) +
geom_text(aes(label = names), position = "fill")
I am using the fivethirtyeight bechdel dataset, located here https://github.com/rudeboybert/fivethirtyeight, and am attempting to recreate the first plot shown in the article here https://fivethirtyeight.com/features/the-dollar-and-cents-case-against-hollywoods-exclusion-of-women/. I am having trouble getting the years to group together similarly to how they did in the article.
This is the current code I have:
ggplot(data = bechdel, aes(year)) +
geom_histogram(aes(fill = clean_test), binwidth = 5, position = "fill") +
scale_fill_manual(breaks = c("ok", "dubious", "men", "notalk", "nowomen"),
values=c("red", "salmon", "lightpink", "dodgerblue",
"blue")) +
theme_fivethirtyeight()
I see where you were going with using the histogram geom but this really looks more like a categorical bar chart. Once you take that approach it's easier, after a bit of ugly code to get the correct labels on the year columns.
The bars are stacked in the wrong order on this one, and there needs to be some formatting applied to look like the 538 chart, but I'll leave that for you.
library(fivethirtyeight)
library(tidyverse)
library(ggthemes)
library(scales)
# Create date range column
bechdel_summary <- bechdel %>%
mutate(date.range = ((year %/% 10)* 10) + ((year %% 10) %/% 5 * 5)) %>%
mutate(date.range = paste0(date.range," - '",substr(date.range + 5,3,5)))
ggplot(data = bechdel_summary, aes(x = date.range, fill = clean_test)) +
geom_bar(position = "fill", width = 0.95) +
scale_y_continuous(labels = percent) +
theme_fivethirtyeight()
ggplot
Here's a bar chart:
ggplot(mtcars) +
geom_bar(aes(x = reorder(factor(cyl), mpg), y = mpg), stat="identity") +
coord_flip()
Should produce this:
I would like to add labels on the end showing the total value of mpg in each bar. For example, 4cyl looks to be around about 290 just from eyeballing. I want to add a label showing the exact number to the bars.
I'd like to experiment and see how they look, so for completeness:
Inside at the top of the bars
Outside the bars along the top
Bonus is I'm able to control whether the labels display vertically or horizontally.
I found this SO post but have struggled to replicate the chosen answer. Here's my attempt:
ggplot(mtcars) +
geom_bar(aes(x = reorder(factor(cyl), mpg), y = mpg), stat="identity") +
coord_flip() +
geom_text(aes(label = mpg))
Which gives an error:
Error: geom_text requires the following missing aesthetics: x, y
How can I add labels to the ends of the bars?
This would do what you need through generating a new data.frame for label plotting. You can customize the location of texts by adjusting nudge_y and angle.
library(dplyr)
tmp <- mtcars %>% group_by(cyl) %>% summarise(tot_mpg = sum(mpg))
tmp$cyl <- factor(tmp$cyl)
ggplot(mtcars) +
geom_bar(aes(x = reorder(factor(cyl), mpg), y = mpg), stat="identity") +
coord_flip() + geom_text(data = tmp, nudge_y = 10, angle = 270,
aes(x = cyl, y = tot_mpg, label = tot_mpg))
I'm hoping to use ggplot2 to generate a set of stacked bars in pairs, much like this:
With the following example data:
df <- expand.grid(name = c("oak","birch","cedar"),
sample = c("one","two"),
type = c("sapling","adult","dead"))
df$count <- sample(5:200, size = nrow(df), replace = T)
I would want the x-axis to represent the name of the tree, with two bars per tree species: one bar for sample one and one bar for sample two. Then the colors of each bar should be determined by type.
The following code generates the stacked bar with colors by type:
ggplot(df, aes(x = name, y = count, fill = type)) + geom_bar(stat = "identity")
And the following code generates the dodged bars by sample:
ggplot(df, aes(x = name, y = count, group = sample)) + geom_bar(stat = "identity", position = "dodge")
But I can't get it to dodge one of the groupings (sample) and stack the other grouping (type):
ggplot(df, aes(x = name, y = count, fill = type, group = sample)) + geom_bar(stat = "identity", position = "dodge")
One workaround would be to put interaction of sample and name on x axis and then adjust the labels for the x axis. Problem is that bars are not put close to each other.
ggplot(df, aes(x = as.numeric(interaction(sample,name)), y = count, fill = type)) +
geom_bar(stat = "identity",color="white") +
scale_x_continuous(breaks=c(1.5,3.5,5.5),labels=c("oak","birch","cedar"))
Another solution is to use facets for name and sample as x values.
ggplot(df,aes(x=sample,y=count,fill=type))+
geom_bar(stat = "identity",color="white")+
facet_wrap(~name,nrow=1)
If I want to order the bars in a ggplot2 barchart from largest to smallest, then I'd usually update the factor levels of the bar category, like so
one_group <- data.frame(
height = runif(5),
category = gl(5, 1)
)
o <- order(one_group$height, decreasing = TRUE)
one_group$category <- factor(one_group$category, levels = one_group$category[o])
p_one_group <- ggplot(one_group, aes(category, height)) +
geom_bar(stat = "identity")
p_one_group
If have have several groups of barcharts that I'd like in different facets, with each facet having bars ordered from largest to smallest (and different x-axes) then the technique breaks down.
Given some sample data
two_groups <- data.frame(
height = runif(10),
category = gl(5, 2),
group = gl(2, 1, 10, labels = letters[1:2])
)
and the plotting code
p_two_groups <- ggplot(two_groups, aes(category, height)) +
geom_bar(stat = "identity") +
facet_grid(. ~ group, scales = "free_x")
p_two_groups
what do I need to do to get the bar ordering right?
If it helps, an equivalent problem to solve is: how do I update factor levels after I've done the faceting?
here is a hack:
two_groups <- transform(two_groups, category2 = factor(paste(group, category)))
two_groups <- transform(two_groups, category2 = reorder(category2, rank(height)))
ggplot(two_groups, aes(category2, height)) +
geom_bar(stat = "identity") +
facet_grid(. ~ group, scales = "free_x") +
scale_x_discrete(labels=two_groups$category, breaks=two_groups$category2)
make UNIQUE factor variable for all entries (category2)
reorder the variable based on the height
plot on the variable: aes(x=category2)
re-label the axis using original value (category) for the variable (category2) in scale_x_discrete.
Here is a hack to achieve what you want. I was unable to figure out how to get the category values below the tick marks. So if someone can help fix that, it would be wonderful. Let me know if this works
# add a height rank variable to the data frame
two_groups = ddply(two_groups, .(group), transform, hrank = rank(height));
# plot the graph
p_two_groups <- ggplot(two_groups, aes(-hrank, height)) +
geom_bar(stat = "identity") +
facet_grid(. ~ group, scales = "free_x") +
opts(axis.text.x = theme_blank()) +
geom_text(aes(y = 0, label = category, vjust = 1.5))