I'm trying to change the shape of the legend key from a geom_bar graph. I've looked at multiple answers online but found they didn't work in this case. Let me explain the problem:
df1 = data.frame(person = c("person1", "person2", "person3"),
variable = "variable1",
value = c(0.5, 0.3, 0.2))
df2 = data.frame(person = c("person1", "person2", "person3"),
variable = "variable2",
value = c(-0.3, -0.1, -0.4))
I'm trying to make a stacked barplot where one side is negative. Using ggplot2 I get:
library(ggplot2)
ggplot() + geom_bar(data = df1, aes(x = person, y = value, fill = variable), stat = "identity") +
geom_bar(data = df2, aes(x = person, y = value, fill = variable), stat = "identity") +
scale_fill_manual(values = c("steelblue", "tomato"), breaks = c("variable1","variable2"),
labels = c("Variable 1", "Variable 2"))
It then looks like this:
Now on the right the legend shows squares by default. Is there a way to change this into a circle for instance?
Online I've found the way this usually works is by using
guides(fill = guide_legend(override.aes = list(shape = 1)))
Or similar variations. However this doesn't seem to work. If anybody can help that would be great, I've been stuck for quite a while now.
You could add a layer of geom_point with no data (just to create a legend) and hide the unwanted rectangular legend from the bars using show.legend = FALSE:
df3 = data.frame(person = as.numeric(c(NA, NA)),
variable = c("variable1", "variable2"),
value = as.numeric(c(NA, NA)))
ggplot() +
geom_bar(data = df1, aes(x = person, y = value, fill = variable), stat = "identity", show.legend = FALSE) +
geom_bar(data = df2, aes(x = person, y = value, fill = variable), stat = "identity", show.legend = FALSE) +
geom_point(data = df3, aes(x = person, y = value, color = variable), size=8) +
scale_fill_manual(values = c("steelblue", "tomato"), breaks = c("variable1","variable2")) +
scale_color_manual(values = c("steelblue", "tomato")) +
theme(legend.key = element_blank())
Related
I am trying to overlay two sets of data that with be used in bar charts. The first is the main set of data and I want that to be the main focus. For the second dataset I want just a line marking where on the chart it would be. I can get close to what I want by doing this:
Tbl = data.frame(Factor = c("a","b","c","d"),
Percent = c(43,77,37,55))
Tbl2 = data.frame(Factor = c("a","b","c","d"),
Percent = c(58,68,47,63))
ggplot(aes(x = Factor, y = Percent), data = Tbl) +
geom_bar(position = "stack", stat = "identity", fill = "blue") +
ylim(0,100) +
geom_bar(aes(x = Factor, y = Percent), data = Tbl2,
position = "stack", stat = "identity", fill = NA, color = "black") +
theme_bw()
What I have so far
I believe I can accomplish what I want by using geom_vline if there is a way to separate it by groups. Another option I came up with is if it is possible to change the colors of the "sides" of the bars in the overlay to white while keeping the "top" of each bar chart as black.
An idea of what I want (Edited in paint)
You could use geom_errorbar where the ymin and ymax are the same values like this:
library(ggplot2)
ggplot(aes(x = Factor, y = Percent), data = Tbl) +
geom_bar(position = "stack", stat = "identity", fill = "blue") +
ylim(0,100) +
geom_errorbar(aes(x = Factor, ymin = Percent, ymax = Percent), data = Tbl2,
stat = "identity", color = "black") +
theme_bw()
Created on 2022-12-28 with reprex v2.0.2
Another option is geom_point with shape = 95 (line) and the size adjusted to suit:
library(tidyverse)
Tbl = data.frame(Factor = c("a","b","c","d"),
Percent = c(43,77,37,55))
Tbl2 = data.frame(Factor = c("a","b","c","d"),
Percent = c(58,68,47,63))
ggplot(aes(x = Factor, y = Percent), data = Tbl) +
geom_bar(position = "stack", stat = "identity", fill = "blue") +
ylim(0,100) +
geom_point(aes(x = Factor, y = Percent), data = Tbl2,
position = "stack", stat = "identity", color = "black", shape = 95, size = 30) +
theme_bw()
Created on 2022-12-28 with reprex v2.0.2
Here is one more using geom_segment(). Some would say to fancy, but anyway:
For this we have to extend Tbl2:
library(ggplot2)
library(dplyr)
ggplot(aes(x = Factor, y = Percent), data = Tbl) +
geom_bar(position = "stack", stat = "identity", fill = "blue") +
ylim(0,100) +
geom_segment(data = Tbl2 %>%
mutate(x = c(0.55, 1.55, 2.55, 3.55),
xend = x+0.9), aes(x=x,xend=xend, y = Percent, yend=Percent), size=2)+
theme_bw()
I want to change the color of my boxplots based on their grouping value or individually instead of the fill value in ggplot. How can I do this? I need to define the fill variable to be able to get the groups subdivided into types, just as I intended, but I cannot seem to control the color anymore.
Here is some example data and how I define the plot:
library(ggplot2)
data <- data.frame( id = rep(1:120),
group = as.factor(rep(1:3, times = 40)),
type = as.factor(rep(1:2, times = 60)),
value = rnorm(120)+1)
ggplot(data, aes(x = group, y = value, fill = type)) +
geom_boxplot(aes(fill = type)) +
geom_point(aes(fill = type), position = position_jitterdodge(dodge.width = 0.65, jitter.width = 0.1, jitter.height = 0.1))
Which results in this image:
Now the colours are based on the "type" grouping. But I would like to control the 6 individual boxplots separately. For example, I want to colour them like this:
colors <- c("#b76e79", "#80a3dd",
"#a5bf9f", "#e3f0cd",
"#8a9a5b", "#ffdead")
Adding scale_fill_manual does not seem to work the way I want.
ggplot(data, aes(x = group, y = value, fill = type)) +
geom_boxplot(aes(fill = type)) +
geom_point(aes(fill = type), position = position_jitterdodge(dodge.width = 0.65, jitter.width = 0.1, jitter.height = 0.1)) +
scale_fill_manual(values = colors)
Any suggestions?
We create a new column by the interaction of 'group', 'type' and use that in scale_fill_manual
library(dplyr)
library(ggplot2)
data <- data %>%
mutate(grptype = interaction(group, type))
gg <- ggplot(data, aes(x = group, y = value, fill = grptype)) +
geom_boxplot(aes(fill = grptype)) +
geom_point(aes(fill = grptype), position = position_jitterdodge(dodge.width = 0.65, jitter.width = 0.1, jitter.height = 0.1))
colors <- c("#b76e79", "#80a3dd",
"#a5bf9f", "#e3f0cd",
"#8a9a5b", "#ffdead")
gg +
scale_fill_manual(name="grptype",
labels = levels(data$grptype),
values = setNames(colors, levels(data$grptype))) +
theme(legend.title = element_text(size=12, color = "black", face="bold"),
legend.justification=c(0,1),
legend.position=c(0.05, 0.95),
legend.background = element_blank(),
legend.key = element_blank())
-output
I have this bar chart:
group = c("A","A","B","B")
value = c(25,-75,-40,-76)
day = c(1,2,1,2)
dat = data.frame(group = group , value = value, day = day)
ggplot(data = dat, aes(x = group, y = value, fill = factor(day))) +
geom_bar(stat = "identity", position = "identity")+
geom_text(aes(label = round(value,0)), color = "black", position = "stack")
and I'd like the bars stacked and the values to show up. When I run the code above the -76 is not in the correct location (and neither is the 75 it seems).
Any idea how to get the numbers to appear in the correct location?
ggplot(data=dat, aes(x=group, y=value, fill=factor(day))) +
geom_bar(stat="identity", position="identity")+
geom_text(label =round(value,0),color = "black")+
scale_y_continuous(breaks=c(-80,-40,0))
Stacking a mix of negative and positive values is difficult for ggplot2. The easiest thing to do is to split the dataset into two, one for positives and one for negatives, and then add bar layers separately. A classic example is here.
You can do the same thing with the text, adding one text layer for the positive y values and one for the negatives.
dat1 = subset(dat, value >= 0)
dat2 = subset(dat, value < 0)
ggplot(mapping = aes(x = group, y = value, fill = factor(day))) +
geom_bar(data = dat1, stat = "identity", position = "stack")+
geom_bar(data = dat2, stat = "identity", position = "stack") +
geom_text(data = dat1, aes(label = round(value,0)), color = "black", position = "stack") +
geom_text(data = dat2, aes(label = round(value,0)), color = "black", position = "stack")
If using the currently development version of ggplot2 (2.1.0.9000), the stacking doesn't seem to be working correctly in geom_text for negative values. You can always calculate the text positions "by hand" if you need to.
library(dplyr)
dat2 = dat2 %>%
group_by(group) %>%
mutate(pos = cumsum(value))
ggplot(mapping = aes(x = group, y = value, fill = factor(day))) +
geom_bar(data = dat1, stat = "identity", position = "stack")+
geom_bar(data = dat2, stat = "identity", position = "stack") +
geom_text(data = dat1, aes(label = round(value,0)), color = "black") +
geom_text(data = dat2, aes(label = round(value,0), y = pos), color = "black")
I want to combine a line and a bar chart with three different variables using ggplot. The bar chart should have the values on top and should be filled with the same colours as the lines in the chart above. Here is my code
# First some data generation
df.x = data.frame(date = Sys.Date()-20:1,
value = c(1:20),
variable = "line",
object = "x")
df.y = data.frame(date = Sys.Date()-20:1,
value = c(1:20)*2,
variable = "line",
object = "y")
df.z = data.frame(date = Sys.Date()-20:1,
value = c(1:20)*3,
variable = "line",
object = "z")
df.y.bar = data.frame(date = Sys.Date()-10,
value = 30,
variable = "bar",
object = "y")
df.x.bar = data.frame(date = Sys.Date()-10,
value = 40,
variable = "bar",
object = "x")
df.z.bar = data.frame(date = Sys.Date()-10,
value = 50,
variable = "bar",
object = "z")
df = rbind(df.x, df.y,df.z, df.x.bar, df.y.bar,df.z.bar)
my.cols = c("blue", "green", "yellow")
# Pass everything to ggplot
ggplot(df, aes_string(x = "date", y = "value", fill="variable")) +
facet_grid(variable~., scales="free_y") +
geom_line(data = subset(df, variable == "line"), aes(colour = factor(object)), size = 1, show_guide = FALSE, stat="identity") +
geom_bar(data = subset(df, variable == "bar"), aes(colour = factor(object)), show_guide = TRUE, stat="identity", position = "dodge") +
geom_text(data = subset(df, variable == "bar"), aes(y=value+0.7 * sign(value), ymax=value, label=round(value, 2)), position = position_dodge(width = 0.9), size=3) +
scale_colour_manual(values = my.cols)
The resulting plot is not exactly what I wanted. I used position_dodge(width = 0.9) but the text over the bars does not move. Irretatingly this does not happen when I only chose two variable (e.g. x and y) to be included in the data frame. The desired result should look like this:
Thanks a lot for your help!
You can fill the bars by choosing fill = factor(object) and adding scale_fill_manual(values = my.cols).
In order to have only one legend I think removing fill="variable" from aes_string did the trick in combination with scale_fill_manual.
And for dodging the text you need to add a group argument and position = position_dodge(width=1)
ggplot(df, aes_string(x = "date", y = "value")) +
facet_grid(variable~., scales="free_y") +
geom_line(data = subset(df, variable == "line"), aes(colour = factor(object)), size = 1, show_guide = FALSE, stat="identity") +
geom_bar(data = subset(df, variable == "bar"), aes(fill = factor(object)), show_guide = TRUE, stat="identity", position = "dodge") +
geom_text(data =subset(df, variable == "bar"), aes(x=date, y=(value+0.7) * sign(value), ymax=value, label=round(value, 2), group=object), position = position_dodge(width=1), size=3) +
scale_colour_manual(values = my.cols) +
scale_fill_manual(values = my.cols)
I have a problem with plot. I want to show only dot points in group A, not in each name. Here is an example:
name <- c("a","b","c","d")
df <- data.frame(id = rep(1:5,3),
value = c(seq(50,58,2),seq(60,68,2),seq(70,78,2)),
name = c(rep("A",5),rep("B",5),rep("C",5)),
type = rep(c("a","b","c","d","r"),3))
df$name <- factor(df$name, levels = c("C","B","A"),ordered = TRUE)
ggplot(df, aes(id, value, fill = name,color = type))+
geom_area( position = 'identity', linetype = 1, size = 1 ,colour="black") +
geom_point(size = 8)+
guides(fill = guide_legend(override.aes = list(colour = NULL, shape = NA)))
If I am reading the question correctly, it seems that you want dots for the blue area only. In that case, you could subset the data and use it for geom_point.
ggplot(df, aes(id, value, fill = name,color = type))+
geom_area( position = 'identity', linetype = 1, size = 1 ,colour="black") +
geom_point(data = subset(df, name == "A"), size = 8) +
guides(fill = guide_legend(override.aes = list(colour = NULL, shape = NA)))