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)
Related
I created a histogram with a number (count) of subjects on the y-axis and I'm trying to find a way to add the ID label of each ID on each bar of the histogram. I tried geom_text and geom_text_repel but I still can't get the number to be organized exactly on each bar for each subject.
For my dataset I'm reading a CSV file with 72 subjects, the columns are ID and Drugratio
ggplot code:
plot_5 <- ggplot(All_data, aes(x=as.numeric(logMRP), fill = as.factor(PATIENTID)))+geom_histogram(aes( bins = 30, label=as.factor(PATIENTID)))+ geom_text( stat='count', aes(label=ID), color="Black", size=3, check_overlap = TRUE, hjust=1, position=position_stack(vjust=0.5 ))+theme(legend.position = "none")
show(plot_5)
Any suggestions!
Thank you
Without your data or code, we can only guess, but it seems your data is something like this:
set.seed(4)
df <- data.frame(ID = factor(1:72), value = 2 - rgamma(72, 3, 2))
And your plotting code is like this:
library(ggplot2)
ggplot(df, aes(value, fill = ID)) +
geom_histogram(bins = 30) +
geom_text(stat = "count", aes(label = ID, y = ..count..),
check_overlap = TRUE) +
guides(fill = guide_none()) +
labs(x = NULL)
This looks very similar to your own plot. To fix it, let's use stat_bin with position = position_stack() for the text layer.
ggplot(df, aes(x = value, fill = ID)) +
geom_histogram(bins = 30) +
stat_bin(geom = "text", bins = 30, na.rm = TRUE,
aes(label = ifelse(after_stat(count) == 0, NA, after_stat(group)),
group = ID, y = after_stat(count)),
position = position_stack(vjust = 0.5)) +
guides(fill = guide_none()) +
labs(x = NULL)
Created on 2022-09-01 with reprex v2.0.2
Following the great suggestions I got from Allan Cameron, I was able to add the ID values for each subject similar to the graphs above
plot_5_new <- ggplot(All_data, aes(x=as.numeric(logMRP), fill = as.factor(ID)))+geom_histogram(bins=30)+ stat_bin(geom = "text", bins = 30, na.rm = TRUE, aes(label = ifelse(after_stat(count) == 0, NA, after_stat(group)), group = as.factor(ID), y = after_stat(count)),position = position_stack(vjust = 0.5)) + guides(fill = guide_none())+theme(legend.position = "none") show(plot_5_new)
So I create a boxplot of data and then add a set point over that data. I want my legend to capture what the data type of the geom_points represents. Thanks!
ggplot(data = NULL) +
geom_boxplot(data = discuss_impact_by_county,
aes(x=reorder(State,discuss, FUN = median),y=discuss),
outlier.shape = NA) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
labs(x = "States") +
geom_point(data = by_state,
aes(x = State, y = discuss_happen_difference),
col = "red",
size = 3,
show.legend = TRUE)
If you want a legend you have to map on aesthetics. In your case map something on the color aes, i.e. move col="red" into aes() and use scale_color_manual to set the value and the legend label to be assgined to the color label "red".
As you have only one "category" of points you can simply do scale_color_manual(values = "red", label = "We are red points") to set the color and label. In case that your have multiple points with different colors it's best to make use of a named vector to assign the colors and legend labels to the right "color label"s, i.e use scale_color_manual(values = c(red = "red"), label = c(red = "We are red points")).
Using some random example data try this:
library(ggplot2)
library(dplyr)
set.seed(42)
discuss_impact_by_county <- data.frame(
State = sample(LETTERS[1:4], 100, replace = TRUE),
discuss = runif(100, 1, 5)
)
by_state <- discuss_impact_by_county %>%
group_by(State) %>%
summarise(discuss_happen_difference = mean(discuss))
#> `summarise()` ungrouping output (override with `.groups` argument)
ggplot(data = NULL) +
geom_boxplot(data = discuss_impact_by_county,
aes(x=reorder(State,discuss, FUN = median),y=discuss),
outlier.shape = NA) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
labs(x = "States") +
geom_point(data = by_state,
aes(x = State, y = discuss_happen_difference, col = "red_points"),
size = 3,
show.legend = TRUE) +
scale_color_manual(values = "red", label = "We are red points")
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())
I want to show histograms of multiple groups where the values do not stack. I do this by:
dat <- data.frame(x = seq(-3, 3, length = 20))
dat$y <- dnorm(dat$x)
dat$z <- dnorm(dat$x, mean = 2)
p <- ggplot(dat, aes(x = x)) +
geom_bar(aes(y = y), stat = "identity", alpha = .5, fill = "red") +
geom_bar(aes(y = z), stat = "identity", alpha = .5, fill = "blue")
I'd like to have a fill legend that shows the groupings. I'm not sure why this does not produce any legend (or error):
p + scale_fill_manual(values = c(x = "red", z = "blue"),
limits = c("mean 0", "mean 2")) +
guides(fill=guide_legend(title.position="top"))
Using unnamed values produces the same result.
Thanks,
Max
The legend is automatically generated only if you map fill to variable using aes, like so:
library(reshape2)
ggplot(melt(dat, "x"), aes(x = x)) +
geom_bar(aes(y = value, fill = variable),
stat = "identity", position = "identity", alpha = .5) +
scale_fill_manual(values = c(y = "red", z = "blue"),
labels = c("mean 0", "mean 2"))
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)))