Please help us sort the stacks in ascending order !
i.e. left facet seems to be in order but right side is not really sorted because 1.7 should have come at the right end. (please refer screenshot)
similar but not exact queries
How to control ordering of stacked bar chart using identity on ggplot2
Order Stacked Bar Graph in ggplot
reorder each facet ascending for a ggplot stacked bar graph
df = data.frame(cat = c(rep("A",9),rep("B",11)),
grp = c(rep("C",3),rep("D",3),rep("F",3), rep("C",3),rep("D",3),rep("E",2),rep("F",3)),
yrs = c(rep(c("2017","2018","2019"),5),"2017","2019","2017","2018","2019"),
per = c(2.4,2.5,3.2,
15.3,17,16.7,
82.4,80.5,80.1,
8.6,9.6,15.2,
36.2,42.2,40.4,
1.7,1.1,53.4,
48.2,43.4))
df %>%
ggplot(aes(x = "scale",y = per, fill = grp)) +
# geom_bar(stat="identity") +
geom_col() +
geom_text(aes(label= round(per,1)),
position=position_stack(vjust=0.5), size= 3) +
facet_grid(vars(yrs),vars(cat)) +
coord_flip() +
theme_bw() +
xlab("") +
ylab("") +
ggtitle("How to sort ") +
theme(legend.position="bottom",
legend.title = element_blank(),
plot.title = element_text(hjust = 0.5),
axis.text = element_blank(),
axis.ticks = element_blank())
By default the bars are ordered alphabetically according to grp. To order by per we can achive this for your case by reordering grp using e.g. fct_reorder from forcats. Note however that with facets this simple solution will not work for more general cases.
library(ggplot2)
library(dplyr)
library(forcats)
df <- data.frame(cat = c(rep("A",9),rep("B",11)),
grp = c(rep("C",3),rep("D",3),rep("F",3), rep("C",3),rep("D",3),rep("E",2),rep("F",3)),
yrs = c(rep(c("2017","2018","2019"),5),"2017","2019","2017","2018","2019"),
per = c(2.4,2.5,3.2,
15.3,17,16.7,
82.4,80.5,80.1,
8.6,9.6,15.2,
36.2,42.2,40.4,
1.7,1.1,53.4,
48.2,43.4))
df %>%
ggplot(aes(x = "scale", y = per, fill = fct_reorder(grp, per))) +
# geom_bar(stat="identity") +
geom_col() +
geom_text(aes(label= round(per,1)),
position=position_stack(vjust=0.5), size= 3) +
facet_grid(vars(yrs),vars(cat)) +
coord_flip() +
theme_bw() +
xlab("") +
ylab("") +
ggtitle("How to sort ") +
theme(legend.position="bottom",
legend.title = element_blank(),
plot.title = element_text(hjust = 0.5),
axis.text = element_blank(),
axis.ticks = element_blank())
Created on 2020-03-17 by the reprex package (v0.3.0)
Related
I want a pie chart instead of a table
method <- dataframe (stringsFactors=FALSE,method=c("violent","nonviolent"),accessiblepeople = (20000,60000)
usage <- dataframe (stringsFactors=FALSE,method=c("violent","nonviolent"),usage = (30%,70%)
ggplot(method, aes(x=method,y=accessiblepeople)+geom_bar(stat="identity")+ggtitle("")+ggpiechart())
Problem add piechart seems not working
You can use plot_grid from the package cowplot to place plots next to each other. I also specified a few features with theme() to remove the gray background so the final plot looks more cohesive.
library(tidyverse)
library(cowplot)
method <- data.frame(method = c("violent", "nonviolent"),
accessiblepeople = c(20000,60000))
bar <- ggplot(method, aes(x = method, y = accessiblepeople, fill = method)) +
geom_bar(stat = "identity") + ggtitle("") +
theme_bw() +
theme(legend.position = "none") +
theme(panel.border = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
axis.line = element_line(color = "black"))
pie <- ggplot(method_df, aes(x="", y=accessiblepeople, fill=method)) +
geom_bar(stat="identity", width=1) +
coord_polar("y", start=0) + theme_void()
plot_grid(bar, pie)
I want to compare automatic and manual cars (mtcars dataset) using a bar plot (ggplot2).
I've got a plot that shows counts on the y-axis (left-hand plot below) but would instead want one with percentages on the y-axis.
I want this so that I can compare cars more easily and say, eg 'models with four cylinders make up x percent of automatic cars but only y percent of manual cars'.
I've tried using this scales package tutorial https://www.tutorialspoint.com/how-to-create-a-bar-plot-using-ggplot2-with-percentage-on-y-axis-in-r for a neat way of changing counts to percentages (right-hand plot below).
The problems that the percentages add up across both the automatic and the manual cars. I want the percentages to add up within automatic and manual cars respectively.
Is there some way of doing that using the scales package or some other package?
Thanks!
# Packages
library(ggplot2)
library(scales)
# Data
data(mtcars)
mtcars$cyl <- as.factor(mtcars$cyl)
mtcars$am <- as.factor(mtcars$am)
# Good counts plot
ggplot(data=mtcars, aes(x=am, fill=cyl)) +
geom_bar(stat="count", position=position_dodge()) + scale_fill_grey() +
ggtitle(expression(bold("mtcars"))) + xlab("automatic or manual") + ylab("count") +
theme(text=element_text(size=20)) +
theme(plot.title = element_text(size = 18, face = "bold"))
# Bad percentages plot
ggplot(data=mtcars, aes(x=am, fill=cyl)) +
geom_bar(aes(y=(..count..)/sum(..count..)), position=position_dodge()) + scale_fill_grey() +
ggtitle(expression(bold("mtcars"))) + xlab("automatic or manual") + ylab("percentage") +
theme(text=element_text(size=20)) +
theme(plot.title = element_text(size = 18, face = "bold"))
I'd only know to calculate the percentage per am manually (using tidyverse):
library(tidyverse)
pl_df <- mtcars %>%
select(am, cyl) %>% # we're only interested in am and cyl
group_by(am, cyl) %>% # group data and
add_count(cyl) %>% # add count of cylinders (per am)
unique() %>% # remove dupliceas
ungroup() %>% # remove grouping
group_by(am) %>% # group by am for...
mutate(cyl_percentage = n/sum(n)) %>% # ...calculating percentage
mutate(cyl = as.factor(cyl)) %>% # change to factors so that ggplot treats...
mutate(am = as.factor(am)) # ...am and cyl as discrete variables
ggplot(data = pl_df, aes(x = am, fill = cyl, y = cyl_percentage)) +
geom_bar(stat = "identity", position=position_dodge()) +
scale_fill_grey() +
ggtitle(expression(bold("mtcars"))) +
xlab("automatic or manual") +
ylab("percentage") +
theme(text=element_text(size=20)) +
theme(plot.title = element_text(size = 18, face = "bold"))
If you want to do the whole thing inside ggplot2 (which is not always the easiest way), you could do:
ggplot(mtcars, aes(x = cyl, group = am, fill = cyl)) +
geom_bar(aes(y = after_stat(prop), fill = factor(after_stat(x)))) +
scale_x_discrete(expand = c(0.5, 0.2)) +
scale_y_continuous(labels = scales::percent) +
scale_fill_manual(values = c("gray25", "gray50", "gray75"),
labels = levels(mtcars$cyl)) +
facet_grid(.~am, switch = "x") +
ggtitle(expression(bold("mtcars"))) +
labs(x = "automatic or manual", y = "percentage") +
theme(text = element_text(size = 20),
plot.title = element_text(size = 18, face = "bold"),
axis.text.x = element_blank(),
axis.ticks.length.x = unit(0, "points"),
panel.spacing = unit(0, "points"),
strip.placement = "outside",
strip.background = element_blank())
I'm trying to recreate a bar graph found on page 4 of the following report:
The figure has three bars with the first two stacked and the third dodged next to it. I've seen iterations of this question but none that recreate the figure in this exact way.
Here is the data:
a <- rep(c('RHB', 'FERS', 'CSRS'), 3)
b <- c(rep('Assets', 3), rep('Amount Past Due', 3),
rep('Actuarial Liability', 3))
c <- c(45.0, 122.5, 152.3, 47.2, 3.4, 4.8, 114.4, 143.4, 181.3)
df <- data.frame(a,b,c)
names(df) <- c('Fund', 'Condition', 'Value')
And what I've managed so far:
p <- ggplot(subset_data, aes(fill=Condition, y=Value, x=Fund)) +
geom_bar(position="stack", stat="identity") +
coord_flip()
I'm not partial to ggplot so if there's another tool that works better I'm ok using another package.
Taking some ideas from the link #aosmith posted.
You can call geom_bar twice, once with Assets and Amounts Past Due stacked, and again with just Actuarial Liability.
You can use width to make the bars thinner, then nudge one set of bars so the two geom_bar calls are not overlapping. I chose to make the width 0.3 and nudge by 0.3 so the edges just line up. If you nudge by more you will see a gap between the two bars.
Edit: add some more formatting and numeric labels
library(tidyverse)
library(scales)
df_al <- filter(df, Condition == 'Actuarial Liability')
df_xal <- filter(df, Condition != 'Actuarial Liability')
bar_width <- 0.3
hjust_lab <- 1.1
hjust_lab_small <- -0.2 # hjust for labels on small bars
ggplot() +
theme_classic() +
geom_bar(data = df_al,
aes(fill=Condition, y=Value, x=Fund),
position = position_nudge(x = -bar_width),
width = bar_width,
stat="identity") +
geom_bar(data = df_xal,
aes(fill=Condition, y=Value, x=Fund),
position="stack",
stat="identity",
width = bar_width) +
geom_text(data = df_al,
aes(label= dollar(Value, drop0trailing = TRUE), y=Value, x=Fund),
position = position_nudge(x = -bar_width),
hjust = hjust_lab) +
geom_text(data = df_xal,
aes(label= dollar(Value, drop0trailing = TRUE), y=Value, x=Fund),
position="stack",
hjust = ifelse(df_xal$Value < 5, hjust_lab_small, hjust_lab)) +
scale_fill_manual(values = c('firebrick3', 'lightsalmon', 'dodgerblue')) +
scale_y_continuous(breaks = seq(0,180, by = 20), labels = dollar) +
coord_flip() +
labs(x = NULL, y = NULL, fill = NULL) +
theme(legend.position = "bottom")
I think I would use the "sneaky facet" method, after adding a dummy variable to dodge the columns and making Fund a factor with the correct order:
df$not_liability <-df$Condition != "Actuarial Liability"
df$Fund <- factor(df$Fund, levels = c('RHB', 'FERS', 'CSRS'))
Most of the plotting code is then an attempt to copy the look of the supplied plot:
ggplot(df, aes(fill=Condition, y=Value, x=not_liability)) +
geom_bar(position = "stack", stat = "identity") +
scale_x_discrete(expand = c(0.5, 0.5)) +
scale_y_continuous(breaks = 0:10 * 20, labels = scales::dollar) +
coord_flip() +
facet_grid(Fund~., switch = "y") +
scale_fill_manual(values = c("#c00000", "#f7c290", "#0071bf"), name = "") +
theme_classic() +
theme(panel.spacing = unit(0, "points"),
strip.background = element_blank(),
axis.text.y = element_blank(),
axis.ticks.length.y = unit(0, "points"),
axis.title = element_blank(),
strip.placement = "outside",
strip.text = element_text(),
legend.position = "bottom",
panel.grid.major.x = element_line())
I am trying to plot three variables and want the units in the axes labels but can't find a way to label them properly in facets with the superscripts.
I've tried as_labeller, label_bquote, expression/paste and changing the original data.
p <- ggplot(data = LST, aes(x = Date, y = Measurements)) +
geom_point((aes(color = parameter)))
p + facet_grid(parameter ~ ., scales = "free_y",
switch="y",labeller=as_labeller(DO~(mg~L^{-1}), Temperature~(°C), Light~
(µmol~m^{-2}~s^{-1}))) +
theme_bw()+ theme(strip.background = element_blank(),
legend.title = element_blank(), strip.placement = "outside",
panel.grid.minor = element_blank()) +
scale_x_datetime()+ ylab(NULL) +ggtitle("Spring 2018") +
scale_colour_manual(values=c('royalblue1', 'springgreen4', 'darkblue')) +
theme(legend.position="none")+
theme(strip.text=element_text(size=10))
Everything I try either labels all facets the same or doesn't place the superscripts. I'm pretty new at ggplot2 so am unsure if what I'm trying will help.
You want labeller = label_parsed. Here's a simple example
mt = mtcars
mt$facets = factor(mt$cyl, labels = c(
"DO~(mg~L^{-1})",
"Temperature~('°C')",
"Light~(µmol~m^{-2}~s^{-1})"))
ggplot(mt, aes(mpg,cyl)) +
geom_point() +
facet_grid(~facets, labeller = label_parsed)
I need to gather two facet columns into one column with ggplot2.
In the following example, I need to overlay the content of the two columns DEG and RAN into one, while giving different colours to DEG and RAN data (small points and smooth line) and provide the corresponding legend (so I can distinguish them as they are overlayed).
I feel my code is not too, too far from what I need, but the relative complexity of the dataset blocks me. How to go about achieving this in ggplot2?
Here's my code so far:
require(reshape2)
library(ggplot2)
library(RColorBrewer)
fileName = paste("./4.csv", sep = "") # csv file available here: https://www.dropbox.com/s/bm9hd0t5ak74k89/4.csv?dl=0
mydata = read.csv(fileName,sep=",", header=TRUE)
dataM = melt(mydata,c("id"))
dataM = cbind(dataM,colsplit(dataM$variable,pattern = "_",names = c("NM", "ORD", "CAT")))
dataM$variable <- NULL
dataM <- dcast(dataM, ... ~ CAT, value.var = "value")
my_palette <- colorRampPalette(rev(brewer.pal(11, "Spectral")))
ggplot(dataM, aes(x=NR ,y= ASPL)) +
geom_point(size = .4,alpha = .5) +
stat_smooth(se = FALSE, size = .5) +
theme_bw() +
theme(plot.background = element_blank(),
axis.line = element_blank(),
legend.key = element_blank(),
legend.title = element_blank()) +
scale_y_continuous("ASPL", expand=c(0,0), limits = c(1, 7)) +
scale_x_continuous("NR", expand=c(0,0), limits = c(0, 100)) +
theme(legend.position="bottom") +
theme(axis.title.x = element_text(vjust=-0.3, face="bold", size=12)) +
theme(axis.title.y = element_text(vjust=1.5, face="bold", size=12)) +
ggtitle("Title") + theme(plot.title = element_text(lineheight=.8, face="bold")) +
theme(title = element_text(vjust=2)) +
facet_grid(NM ~ ORD)
Here's what it gives me right now:
Extra question: how come DEG/SF doesn't show a smooth line?
You can use the group aesthetic to define that data points with the same value of ORD belong together. You can also map aesthetics shape and color to this variable. You can also use . to specify that the facets are not split along a specific dimension.
I have made the changes to your code below after transforming NR and ASPL to numeric variables:
dataM$NR <- as.integer(dataM$NR)
dataM$ASPL <- as.numeric(dataM$ASPL)
ggplot(dataM, aes(x=NR ,y= ASPL, group=ORD, color=ORD)) +
geom_point(size = .7,alpha = .5, aes(shape=ORD)) + ## increased size
stat_smooth(se = FALSE, size = .5) +
theme_bw() +
theme(plot.background = element_blank(),
axis.line = element_blank(),
legend.key = element_blank(),
legend.title = element_blank()) +
scale_y_continuous("ASPL", expand=c(0,0), limits = c(1, 7)) +
scale_x_continuous("NR", expand=c(0,0), limits = c(0, 100)) +
theme(legend.position="bottom") +
theme(axis.title.x = element_text(vjust=-0.3, face="bold", size=12)) +
theme(axis.title.y = element_text(vjust=1.5, face="bold", size=12)) +
ggtitle("Title") + theme(plot.title = element_text(lineheight=.8, face="bold")) +
theme(title = element_text(vjust=2)) +
facet_grid(NM ~.)