Reputation: 71
I would like to overlay 2 bar charts in Plotly (R), but cannot figure it out. Can easily be done in ggplot2, but qqplotly renders it incorrectly so I would like to make the chart in plot_ly. Thanks for any suggestions.
data:
df = data.frame(
year = c(2014,2014,2014,2015,2015,2015,2016,2016,2016),
pet = c("dog","cat","bird","dog","cat","bird","dog","cat","bird"),
wt_before = c(56, 25, 26, 10, 19, 41, 16, 17, 13),
wt_after = c(49, 18, 19, 3, 12, 34, 9, 10, 6)
)
ggplot:
ggplot(df)+
geom_bar(aes(year,wt_before,fill=pet),stat="identity",position="dodge",width = 0.9,alpha=0.5)+
geom_bar(aes(year,wt_after,fill=pet),stat="identity",position="dodge",width = 0.9)+
xlab("Year") +
ylab("Weight")
plotly attempt:
plot_ly(df,x= ~year) %>%
add_bars(y= ~wt_before, color = ~pet, alpha = 0.5) %>%
add_bars(y= ~wt_after, color = ~pet, showlegend=FALSE) %>%
layout(xaxis=list(title="Year"),
yaxis=list(title="Weight"))
Upvotes: 6
Views: 3448
Reputation: 31659
As Mike Wise pointed out, it's not a stacked plot but an overlayed bar chart which might lead to weird results (what if the pet gained weight? this kind of information would be lost in the graph). You could plot the weight before and after next to each other, that's more informative and covers all cases.
But let's assume we just want to have a stacked bar chart with multiple identical categorical x-values.
Each bar chart would need to be plotted with "virtual" x-values, i.e a position which is composed of the year (seq
) and the animal (i
):
xaxis_length <- length(unique(df$year))
animal_no <- length(unique(df$pet))
i <- 0
for (animal in unique(df$pet)) {
x <- seq(0,
animal_no * xaxis_length + xaxis_length,
by = xaxis_length + 1) + i
i <- i + 1
}
Those x-values can be used to plot the bars, one bar for the base line, one for the difference (by subtracting the two dataframe columns).
for (animal in unique(df$pet)) {
x <- seq(0,
animal_no * xaxis_length + xaxis_length,
by = xaxis_length + 1) + i
i <- i + 1
p <- add_trace(p,
data=df[df$pet == animal, ],
x = x,
y = ~wt_after,
type = 'bar'
)
p <- add_trace(p,
data=df[df$pet == animal, ],
x = x,
y = df[df$pet == animal, ]$wt_before - df[df$pet == animal, ]$wt_after,
type = 'bar'
)
}
Only for the relevant x-axis ticks the values are shown.
layout(barmode = 'stack',
xaxis=list(ticktext = unique(df$year),
tickvals = seq(1,
xaxis_length * animal_no + xaxis_length,
by = xaxis_length + 1)
),
bargap = 0)
The colors are created by using a list of colors and setting one to half transparent and other not transparent at all.
colors <- c('rgba(97,156,255,',
'rgba(0,186,56,',
'rgba(248,118,109,')
marker=list(color = paste(colors[[animal]],
",0.5)",
sep = "")
Complete code
library(plotly)
df = data.frame(
year = c(2014, 2014, 2014, 2015, 2015, 2015, 2016, 2016, 2016, 2017, 2017, 2017),
pet = c("dog", "cat", "bird", "dog", "cat", "bird", "dog", "cat", "bird", "dog", "cat", "bird"),
wt_before = c(56, 25, 26, 10, 19, 41, 16, 17, 13, 20, 25, 30),
wt_after = c(49, 18, 19, 3, 12, 34, 9, 10, 6, 15, 20, 22)
)
colors <- c('rgba(97,156,255,',
'rgba(0,186,56,',
'rgba(248,118,109,')
xaxis_length <- length(unique(df$year))
animal_no <- length(unique(df$pet))
names(colors) <- unique(df$pet)
p <- plot_ly() %>% layout(barmode = 'stack') %>%
layout(barmode = 'stack',
xaxis=list(ticktext = unique(df$year),
tickvals = seq(1,
xaxis_length * animal_no + xaxis_length,
by = xaxis_length + 1)
),
bargap=0)
i <- 0
for (animal in unique(df$pet)) {
x <- seq(0,
animal_no * xaxis_length + xaxis_length,
by = xaxis_length + 1) + i
i <- i + 1
p <- add_trace(p,
data=df[df$pet == animal, ],
x = x,
y = ~wt_after,
type = 'bar',
name = animal,
marker = list(color = paste(colors[[animal]],
",1)",
sep = "")
),
legendgroup = animal,
text = ~wt_after,
hoverinfo = 'text'
)
p <- add_trace(p,
data=df[df$pet == animal, ],
x = x,
y = df[df$pet == animal, ]$wt_before - df[df$pet == animal, ]$wt_after,
type = 'bar',
name = animal,
marker=list(color = paste(colors[[animal]],
",0.5)",
sep = "")
),
legendgroup = animal,
showlegend = FALSE,
text = ~wt_before,
hoverinfo = 'text'
)
}
p
Upvotes: 6