ggplot2: change strip.text position in facet_grid plot - r

you can set the position of the legend inside the plotting area, like
... + theme(legend.justification=c(1,0), legend.position=c(1,0))
Is there a similarly easy way to change the position of the strip text
(or factor levels in grouped plots)
library(reshape2); library(ggplot2)
sp <- ggplot(tips, aes(x=total_bill, y=tip/total_bill)) + geom_point() +
facet_grid(. ~ sex)
sp
(http://www.cookbook-r.com/Graphs/Facets_%28ggplot2%29/)
in lattice I would use something like strip.text = levels(dat$Y)[panel.number()]
and panel.text(...), but there may be a cleaner way too...
thx, Christof

Here's one approach:
ggplot(tips, aes(x = total_bill, y = tip / total_bill)) +
geom_point() +
facet_grid(. ~ sex) +
geom_text(aes(label = sex), x = Inf, y = Inf, hjust = 1.5, vjust = 1.5) +
theme(
strip.background = element_blank(),
strip.text = element_blank()
)
However, this is not moving the strip.text, rather, it's adding a geom_text element and turning off the strip.background and strip.text, but I think it achieves the desired outcome.

A slight addition to #JasonAizkalns is to add the check_overlap = T option in geom_text, to avoid the superposition of multiple identical labels.
ggplot(tips, aes(x = total_bill, y = tip / total_bill)) +
geom_point() +
facet_grid(. ~ sex) +
geom_text(aes(label = sex), x = Inf, y = Inf, hjust = 1.5, vjust = 1.5, check_overlap = TRUE) +
theme(
strip.background = element_blank(),
strip.text = element_blank()
)

Related

R ggplot2 package: plotting Line (geom_line)over on Bar Graph (geom_bar) from separate data frames

I have a bar graph (created using ggplot2 package) coming from one set of yearly data (with multiple y values)and I want to overlay on it data from another set of yearly data in the form of a line. Here is my code:
library (zoo)
require(ggplot2)
library(reshape)
library(Cairo)
library(reshape2)
x<-c(2000,2001,2002,2003,2004)
y1<-c(41,62,71,316,172)
y2<-c(3018,2632,2643,2848,2738)
y3<-c(3065,2709,2721,3192,2925)
dat1 <- data.frame(Year=x, y1, y2)
dat.m1 <- melt(dat1, id.vars='Year')
a<-ggplot(dat.m1, aes(Year, value)) +
geom_bar(width=0.6,aes(fill = variable),stat = "identity")+
xlab("Year") + ylab("Water Depth (mm)")+
theme(legend.position="top")+
theme(panel.background = element_rect(fill = 'white', colour = 'black'))+
theme(axis.text=element_text(size=13),axis.title=element_text(size=14))+
theme(legend.text=element_text(size=14))+
theme(plot.margin=unit(c(0.2,0.7,0.5,0.2),"cm"))+
guides(fill = guide_legend(title="", title.position="top", direction="horizontal"))
a
At this stage, bar plot is running nicely but when I tried to add line plot from different data frame as follow:
dat2 <- data.frame(Year=x, y3)
dat.m2 <- melt(dat2, id.vars='Year')
b<-ggplot(dat.m1, aes(Year, value)) +
geom_bar(width=0.6,aes(fill = variable),stat = "identity")+
geom_line(dat.m2, aes(x = x, y = y3), size = 1.5, color="red") +
xlab("Year") + ylab("Water Depth (mm)")+
theme(legend.position="top")+
theme(panel.background = element_rect(fill = 'white', colour = 'black'))+
theme(axis.text=element_text(size=13),axis.title=element_text(size=14))+
theme(legend.text=element_text(size=14))+
theme(plot.margin=unit(c(0.2,0.7,0.5,0.2),"cm"))+
guides(fill = guide_legend(title="", title.position="top", direction="horizontal"))
b
It did not work and I received this error message:
"Error in validate_mapping():
! mapping must be created by aes()
Run rlang::last_error() to see where the error occurred."
Anyone can help me to fix this issue? Also, any suggestion to add a line plot with each bar in the first data frame?
You need to add argument name data in geom_line(). Otherwise dat.m2 is received as mapping to the geom_line function.
dat2 <- data.frame(Year = x, y3)
dat.m2 <- melt(dat2, id.vars = 'Year')
b <- ggplot(dat.m1, aes(Year, value)) +
geom_bar(width = 0.6, aes(fill = variable), stat = "identity") +
geom_line(data = dat.m2, aes(x = x, y = y3), size = 1.5, color = "red") + # adding data argument name
xlab("Year") + ylab("Water Depth (mm)") +
theme(legend.position = "top") +
theme(panel.background = element_rect(fill = 'white', colour = 'black')) +
theme(axis.text = element_text(size = 13),
axis.title = element_text(size = 14)) +
theme(legend.text = element_text(size = 14)) +
theme(plot.margin = unit(c(0.2, 0.7, 0.5, 0.2), "cm")) +
guides(fill = guide_legend(
title = "",
title.position = "top",
direction = "horizontal"
))
b

Adjust the position of each text to the top center of its grouped vertical bar plot columns in ggplot2

By the code below, I generate a grouped bar plot below:
df <- data.frame(Person = c("Mr.A","Mr.B"), Cats = c(3,4), Dogs = c(1,2))
data.m <- melt(df, id.vars='Person')
ggplot(data.m, aes(Person, value)) +
geom_bar(aes(fill = variable), width = 0.4, position = position_dodge(width=0.5), stat="identity") +
geom_text(
aes(x = Person, y = value, label=value),
position = position_dodge(width=1),
# position = 'dodge',
# hjust=-1,
vjust=-0.25) +
theme(legend.position="top",
legend.title = element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank())
Now my question is how could we adjust the text in the middle of each bar column (as the arrows shown in the figure above), I tried by paramters: position=position_dodge(width=1), position='dodge', hjust=-1 and hjust=1, it seems not working. Someone could help? Thanks.
Reference:
Aligning geom_text in grouped dodged barplot
You need to specify group=variable in geom_text.
ggplot(data.m, aes(Person, value)) +
geom_bar(aes(fill = variable), width = 0.4, position = position_dodge(width=0.5), stat="identity") +
geom_text(
aes(x = Person, y = value, label=value, group = variable),
position = position_dodge(width=0.5),
# position = 'dodge',
# hjust=-1,
vjust=-0.25) +
theme(legend.position="top",
legend.title = element_blank(),
axis.title.x=element_blank(),
axis.title.y=element_blank())

Bar graph: Combine one stacked bar with one dodged bar

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())

Broken confidence interval areas when using ylim in ggplot2

I've been using ggplot2 for long, but never experienced this issue. I am representing confidence intervals of some regressions. However, I decided to manually control the ylim(). I realized that those areas which exceed the y limits are broken. See this picture:
The red regression on the right contains a very wide CLs. As you can see there is a gap in there as its highest point is outside ylim range.
This is the code I used:
ggplot(dataset, aes(x=variable, y=value, fill=Species, colour=Species, linetype = Species)) +
geom_smooth(method="lm", formula= y~poly(x,3), level=0.95, alpha=0.2) +
xlab("A") +
ylab("B") +
ylim(0, 30) +
theme(axis.text.x = element_text(angle = 0, hjust = 0.5, size = 10),
panel.background = element_blank(),
legend.position='bottom',
panel.grid.major = element_line(colour="azure2"),
axis.line = element_line(colour = "black",
size = 0.15, linetype = "solid")) +
scale_x_continuous(breaks=seq(1, 10, 1), limits=c(1, 10)) +
scale_color_manual(values=c("coral4", "coral1", "darkolivegreen3", "darkgoldenrod4", "darkgoldenrod2", "deepskyblue3", "darkorchid3")) +
scale_fill_manual(values=c("coral4", "coral1", "darkolivegreen3", "darkgoldenrod4", "darkgoldenrod2", "deepskyblue3", "darkorchid3")) +
scale_linetype_manual(values=c(1,1,1,3,3,2,2))
I would like to keep these y limits. I used coord_cartesian with no success. Can anybody help me?
coord_cartesian should work, but you have to remove the ylim()
Some data
set.seed(1)
df <- data_frame(x = -5:5, y = rnorm(11, x^2, 5))
Replicating your problem
ggplot(df, aes(x, y)) +
geom_smooth() +
ylim(-1, NA)
With coord_cartesian
ggplot(df, aes(x, y)) +
geom_smooth() +
coord_cartesian(ylim = c(-1, 40))

Split parts of a stacked barplot into individual series

I want to create in R 3.2.2 a barplot with stacked bars but with each part of each bar splitted into an individual series.
Example data frame:
num_var_x = 14
num_var_y = 17
x = runif(num_var_x, 0.0, 1.0)
norm = x/sum(x)
data = data.frame(replicate(num_var_y,sample(norm)))
EDIT:
Thanks to Floo0 I have come up with this continuation of the code:
## preparing dataset for ggplot
require(ggplot2)
require(reshape2)
data$no <- seq_len(nrow(data))
data_molten <- melt(data, id.vars = "no")
data_molten_sort = data_molten[with(data_molten,order(no)),]
## removing elements from variable 'no' whose max. value is e.g. < 0.025
sequence = seq(from=1, to=(num_var_y*num_var_x-num_var_x)+1, by=num_var_x)
for(i in 1:length(sequence))
{
if(isTRUE((max(data_molten_sort$value[(sequence[i]):((num_var_x+sequence[i])-(1))])) < 0.025))
{
data_molten_sort$value[(sequence[i]):((num_var_x+sequence[i])-(1))] = NA
}
}
View(data_molten)
## preparing posterior exporting
#install.packages("Cairo"); "cairo" type in png() has a better quality
library("Cairo")
#preparing exporting
png(file="ggplot.png",type="cairo", width = 4, height = 5, units = 'in',pointsize=8,res=600)
## plotting
ggplot(data_molten[!is.na(data_molten$value),], aes(x = variable, y = value, fill = factor(no))) +
geom_bar(stat = "identity") +
scale_fill_hue(l=40) + facet_grid(no~., as.table=FALSE, scale="free_y", space = "free_y") + theme_minimal() +
geom_vline(xintercept=max(as.numeric(data_molten$variable)) + 0.586, size=0.3) +
theme(legend.position="none",
axis.text.x = element_text(angle = 90, colour="black", vjust = 0.4, hjust=1, size=8),
axis.title.x = element_blank(), axis.title.y = element_blank(),
axis.line.y=element_blank(), axis.text.y=element_blank(), axis.ticks.y=element_blank(),
strip.text.y=element_text(size = 8, colour="black", family="", angle=00,hjust = 0.1),
panel.grid=element_blank(),
axis.line=element_line(size = 0.3, colour = "black", linetype = "solid"),
axis.ticks.x=element_line(size = 0.3, colour = "black", linetype = "solid"),
panel.background=element_blank(), panel.margin = unit(0, "lines"))
## exporting barplot "ggplot.png" to directory
dev.off()
which produces the desired barplot:
http://i.imgur.com/C6h5fPg.png?1
You can use ggplot2 to do that as follows:
require(ggplot2)
require(reshape2)
data$no <- seq_len(nrow(data))
data_molten <- melt(data, id.vars = "no")
If you want the rows to have different hights, have a look at: Different y-Axis Labels facet_grid and sizes
I am not 100% sure in which direction you want the plot to be turned:
Version 1
ggplot(data_molten, aes(x = no, y = value, fill = variable)) + geom_bar(stat = "identity") +
facet_grid(variable~.) + theme(legend.position="none")
Version 2
Thx bergant fot the comment
ggplot(data_molten, aes(x = variable, y = value, fill = factor(no))) + geom_bar(stat = "identity") +
facet_grid(no~.) + theme(legend.position="none")
Original
ggplot(data_molten, aes(x = no, y = value, fill = variable)) + geom_bar(stat = "identity")

Resources