overlapping line and bar charts at the dame time with ggplot - r

Would like to overlap a line chart over a bar chart with ggplot.
Say, V1, V2 are the data for the bar charts, and V3 shall be presented as line.
How can I complete the subset and different geom at the same time?
library(data.table)
library(ggplot2)
set.seed(100)
dat <- data.frame(Axis=letters[1:10],V1=1:10, V2=runif(10, 1,10), V3=10:1)
dat <-melt(data,id.var="Axis",measure.var=c("V1","V2","V3"))
Would it be like this?
ggplot(dat, aes(x=Axis)) +
geom_bar(stat="identity", aes(, y= value[------]))+ # V1, V2 for bars
geom_line(aes(y=value[-----)) # V3 for line
I tried making the subset of V1, V2, and make a bar chart, but can't insent V3 as a line on the chart.
Many thanks
Thanks to #dash2, I slightly changed his code, and make it looks clearer.
ggplot(dat, aes(x = Axis)) +
geom_col(aes(y = V1), fill = "darkred", alpha = .5, width=0.4) +
geom_col(aes(y = V2), fill = "blue", alpha = .5,
position = position_nudge(x = 0.4),width=0.4) +
geom_line(aes(y = V3, group = NA))

Simplest, no melting.
ggplot(data, aes(x = Axis)) +
geom_col(aes(y = V1), fill = "darkred", alpha = .5) +
geom_col(aes(y = V2), fill = "blue", alpha = .5,
position = position_nudge(x = 0.2)) +
geom_line(aes(y = V3, group = NA))
Add aesthetics to taste.
The group argument is necessary. I think that discrete scales (like the x axis here) automatically group their values, leaving you with groups of 1 and no lines being drawn... consistent, but unintuitive.

No need to melt your data, just simply add different aesthetics to each geom:
data <- data.frame(Axis=letters[1:10], V1=1:10, V2=runif(10, 1,10), V3=10:1)
ggplot(data, aes(x = V1)) +
geom_col(aes(y = V2)) +
geom_line(aes(y = V3))

How about this
library(data.table)
library(ggplot2)
set.seed(100)
data <- tibble(Axis=letters[1:10],V1=1:10, V2=runif(10, 1,10), V3=10:1)
data <-melt(data,id.var="Axis",measure.var=c("V1","V2","V3"))
glimpse(data)
ggplot(data, aes(x=Axis, y= data$value)) +
geom_bar(aes(fill = variable), stat="identity")

Another option could be with melt data as:
library(data.table)
library(ggplot2)
set.seed(100)
data <- data.frame(Axis=letters[1:10],V1=1:10, V2=runif(10, 1,10), V3=10:1)
data <-melt(data,id.var="Axis",measure.var=c("V1","V2","V3"))
library(dplyr)
ggplot() +
geom_bar(data=filter(data, variable %in% c("V1", "V2")),
aes(x = Axis, y = value, fill=variable), stat ="identity", position="dodge") +
geom_line(data=filter(data, variable == "V3"),
aes(x = Axis, y = value, colour = variable, group=variable))

Related

How to correctly specify a column as the fill colour in geom_ribbon?

I can't seem to be able to set different fill colours for geom_ribbon(), using one of the columns as input to fill
library(ggplot2)
time <- as.factor(c('A','B','C','D'))
grouping <- as.factor(c('GROUP1','GROUP1','GROUP1','GROUP1',
'GROUP2','GROUP2','GROUP2','GROUP2'))
x <- c(1.00,1.03,1.03,1.06,0.5,0.43,0.2,0.1)
x.upper <- x+0.05
x.lower <- x-0.05
df <- data.frame(time, x, x.upper, x.lower,grouping)
ggplot(data = df,aes(as.numeric(time),x,group=grouping,color=grouping)) +
geom_ribbon(data = df, aes(x=as.numeric(time), ymax=x.upper, ymin=x.lower),
fill=grouping, alpha=.5) +
geom_point() + labs(title="My ribbon plot",x="Time",y="Value") +
scale_x_continuous(breaks = 1:4, labels = levels(df$time))
I get the error Error: Unknown colour name: grouping but fill=c("pink","blue") works fine. I don't want to specify the colours manually.
All other examples I can find simply list the column in the fill argument so I'm not sure what I'm doing incorrectly.
Move fill = grouping inside aes so that this column is mapped to the fill variable.
ggplot(data = df, aes(as.numeric(time), x, color = grouping)) +
geom_ribbon(data = df, aes(ymax = x.upper, ymin = x.lower,
fill = grouping), alpha = 0.5) +
geom_point() +
labs(title = "My ribbon plot", x = "Time", y = "Value") +
scale_x_continuous(breaks = 1:4, labels = levels(df$time))

modify horizontal barplots for combination (tight design)

I have the following sample data:
library(tidyverse)
df <- data.frame(col=rep(c("A_B", "A_C", "A_D",
"B_A", "C_A", "D_A",
"B_C", "B_D",
"C_B", "D_B",
"C_D", "D_C"), 2),
level=c(rep("lower_level", 12), rep("higher_level", 12)),
value=abs(rnorm(24, mean=5, sd=2)))%>% tibble()
df[c('origin', 'target')] <- str_split_fixed(df$col, '_', 2)
df <- df %>% select(c(origin, target, level, value))
I now want to create horizontal stacked barplots for each target (df %>% filter(target=="A")). I do this using the following code:
# plot
p1 <- ggplot(data = df %>% filter(target=="A"),
aes(x = factor(level), y = value, fill = factor(origin)))+
geom_bar(stat="identity", position="fill", width = .1) +
scale_fill_manual(values = c("A"="yellow", "B" = "green", "C"="red", "D"="blue")) +
coord_flip()
Since I want to combine multiple such plots later (s. below), I would like to
remove the empty space between y-axis and the bars (or manipulate it to value X)
have the fill label displayed on the right side
have one value on the left, saying "target: A"
and have fill legend and y axis shared between all plots.
See annotated plot:
For reference, I create additional plots with this code:
p2 <- ggplot(data = df %>% filter(target=="B"),
aes(x = factor(level), y = value, fill = factor(origin)))+
geom_bar(stat="identity", position="fill", width = .1) +
scale_fill_manual(values = c("A"="yellow", "B" = "green", "C"="red", "D"="blue")) +
coord_flip()
p3 <- ggplot(data = df %>% filter(target=="C"),
aes(x = factor(level), y = value, fill = factor(origin)))+
geom_bar(stat="identity", position="fill", width = .1) +
scale_fill_manual(values = c("A"="yellow", "B" = "green", "C"="red", "D"="blue")) +
coord_flip()
p4 <- ggplot(data = df %>% filter(target=="D"),
aes(x = factor(level), y = value, fill = factor(origin)))+
geom_bar(stat="identity", position="fill", width = .1) +
scale_fill_manual(values = c("A"="yellow", "B" = "green", "C"="red", "D"="blue")) +
coord_flip()
And combine them with this code (but happy to use other ways of combining them if needed).
library("gridExtra")
grid.arrange(p1, p2, p3, p4, ncol = 1, nrow = 4)
It sounds very much as though you simply want to facet by target. No need for stitching multiple plots here.
ggplot(data = df %>% mutate(target = paste('Target:', target)),
aes(x = factor(level), y = value, fill = factor(origin)))+
geom_col(position = "fill", width = 0.9) +
scale_fill_manual(values = c("A"="yellow", "B" = "green",
"C"="red", "D"="blue"), name = 'origin') +
facet_grid(target~., switch = 'y') +
coord_flip() +
theme(strip.placement = 'outside',
strip.background = element_blank(),
axis.title.y = element_blank())
two suggestions_
to remove the offset between axis and bar, set the axis expansion to zero
scale_x_continuous(..., expand = c(0,0))
instead of tediously subsetting the data frame, use the facet_wrap or facet_grid option of ggplot:
ggplot(data = df,
aes(x = factor(level), y = value, fill = factor(origin))) +
## other plot instructions
facet_wrap( ~target)
see ?facet_wrap for various layout options like number of plot columns
3. the vertical spacing between bars will be adjusted to the output dimensions (here: figure height) anyway

geom_bar and geom_point in the same ggplot and within the same groups

I have the current code
ggplot(data = niveles[niveles$departamento=="CUNDINAMARCA" &
niveles$prueba=="MATEMÁTICAS" &
!is.na(niveles$nivel),]) +
geom_bar(stat="identity", position = position_dodge(),
aes(x = año, y = desempeño, fill = nivel)) +
geom_point(data = niveles[niveles$prueba=="MATEMÁTICAS" &
niveles$departamento=="COLOMBIA" &
!is.na(niveles$nivel),], shape = 24,
aes(x = año, y = desempeño, group = nivel, fill = "blue"))
which gives me the following plot:
However, I was hoping to get each one of the "points" withing its corresponding category of the "niveles" variable. Does anyone know how I can do that?
You can dodge points the same way as you dodge bars using position=position_dodge(). However, you need to add a width argument specifying how much to "dodge". A value of 1 should correspond with the dodged bars. You also have an unknown "blue" category in the legend. That's because the fill argument should appear outside the aesthetic (aes)
I also think you should subset the data first instead of doing all that within the ggplot command.
An alternative is to facet by department (see option 2 below).
But first to dodge the points.
Option 1: Subsetting
Create a subset for prueba and non-missing for nivel:
MATH <- niveles[niveles$prueba=="MATEMÁTICAS" & !is.na(niveles$nivel),]
Create subsets for each department:
CUNDINAMARCA <- MATH[MATH$departamento=="CUNDINAMARCA",]
COLOMBIA <- MATH[MATH$departamento=="CUNDINAMARCA",]
Then make your graph:
ggplot(data = CUNDINAMARCA) +
geom_bar(stat="identity", position = position_dodge(),
aes(x = año, y = desempeño, fill = nivel)) +
geom_point(data = COLOMBIA, shape = 24,
position = position_dodge(width=1), # You need this to align points with bars
aes(x = año, y = desempeño, group = nivel), fill = "blue")
I can't test it on your data but I used the mtcars dataset as an example.
mtcars <- mtcars %>%
mutate(gear=factor(gear), cyl=factor(cyl))
VS0 <- mtcars[mtcars$vs==0,]
VS1 <- mtcars[mtcars$vs==1,]
ggplot() +
geom_bar(data = VS0, stat="identity", position = position_dodge(),
aes(x = cyl, y = mpg, fill = gear)) +
geom_point(data = VS1, shape = 24,
position = position_dodge(width=1),
aes(x = cyl, y = mpg, group = gear), fill = "blue")
Option 2: Facetting
ggplot(data = mtcars, group=vs) +
geom_bar(stat="identity", position = position_dodge(),
aes(x = cyl, y = mpg, fill = gear)) +
facet_grid(~vs, labeller=label_both)
For your data, maybe this would work:
DATA <- MATH[MATH$departamento %in% c("CUNDINAMARCA","COLOMBIA"),]
ggplot(data = DATA, group=departamento) +
geom_bar(stat="identity", position = position_dodge(),
aes(x = año, y = desempeño, fill = nivel)) +
facet_grid(~departamento, labeller=label_both)

How to stack a level in a bar chart?

I'm trying to build a stacked bar chart from a 2x2 dataframe. I'm using ggplot2 1.0.0. Unfortunately, the column with data for the B level only shows one colour, instead of two.
df <- data.frame(x1 = rep(c("A","B"), each = 2), x2 = c(75.0, 25.0, 50.0, 50.0))
fig1 <- ggplot(data = df, aes(x = x1, y = x2)) + geom_bar(aes(x1, fill = x2), stat = "identity") + xlab("") + ylab("%") + ggtitle("df")
fig1 + geom_text(aes(label = x2), vjust = -0.8, colour = "white")
The code produces the following graph: http://imgur.com/j3DEO5h
Any ideas?
You used a continous scale for fill, so two 50 values have the same colour. You could use a discrete scale like this:
ggplot(transform(df, var = as.factor(1:2)),
aes(x = x1, y = x2, fill = var)) +
geom_bar(stat = "identity")

Annotation above bars:

dodged bar plot in ggplot again has me stumped. I asked about annotating text above bars on here a few weeks back (LINK) and got a terrific response to use + stat_bin(geom="text", aes(label=..count.., vjust=-1)). I figured since I already have the counts I'll just supply them with out the .. before and after and I told stat_bin that the position was dodge. It lines them up over the center of the group and adjusts up and down. Probably something minor. Please help me to get the text over the bars.
mtcars2 <- data.frame(type=factor(mtcars$cyl),
group=factor(mtcars$gear))
library(plyr); library(ggplot)
dat <- rbind(ddply(mtcars2,.(type,group), summarise,
count = length(group)),c(8,4,NA))
p2 <- ggplot(dat,aes(x = type,y = count,fill = group)) +
geom_bar(colour = "black",position = "dodge",stat = "identity") +
stat_bin(geom="text", aes(position='dodge', label=count, vjust=-.6))
I was having trouble getting the position dodges to line up, so I ended up creating a position_dodge object (is that the right terminology?), saving it to a variable, and then using that as the position for both geoms. Somewhat infuriatingly, they still seem to be a little off centre.
dodgewidth <- position_dodge(width=0.9)
ggplot(dat,aes(x = type,y = count, fill = group)) +
geom_bar(colour = "black", position = dodgewidth ,stat = "identity") +
stat_bin(geom="text", position= dodgewidth, aes(x=type, label=count), vjust=-1)
Updated geom_bar() needs stat = "identity"
I think this does what you want as well.
mtcars2 <- data.frame(type = factor(mtcars$cyl), group = factor(mtcars$gear))
library(plyr); library(ggplot2)
dat <- rbind(ddply(mtcars2, .(type, group), summarise, count = length(group)), c(8, 4, NA))
p2 <- ggplot(dat, aes(x = type,y = count,fill = group)) +
geom_bar(stat = "identity", colour = "black",position = "dodge", width = 0.8) +
ylim(0, 14) +
geom_text(aes(label = count, x = type, y = count), position = position_dodge(width = 0.8), vjust = -0.6)
p2

Resources