I need to make a graph with multiple kinds of data on it, and I'm plotting one type of data with lines and one type with points. I've added a manually specified legend to show which type is points and which is lines (admittedly, my approach is a bit hacky), and that's working except for the legend order. Here's a dummy example:
DF1 <- data.frame(X = 1:10,
Y = c(1:10*0.5, 1:10*0.25),
Fruit = rep(c("mango", "kiwi"), each = 10))
DF2 <- data.frame(X = 1:10,
Y = c(1:10*2, 1:10*4),
Cat = rep(c("tabby", "calico"), each = 10))
Empty <- data.frame(X = mean(DF$X),
Y = as.numeric(NA),
# Q = c(0, 1))
Type = c("Cat", "Fruit"))
Mygraph <- ggplot(DF1, aes(x = X, y = Y, color = Fruit)) +
geom_point() +
geom_line(data = DF2, aes(x = X, y = Y, linetype = Cat),
inherit.aes = F) +
labs(color = NULL, linetype = NULL) +
geom_point(data = Empty, aes(x = X, y = Y, alpha = Type),
inherit.aes = F) +
geom_line(data = Empty, aes(x = X, y = Y, alpha = Type),
inherit.aes = F) +
scale_alpha_manual(
name = "Type of item", values = c(1, 1),
breaks = c("Fruit", "Cat"),
guide = guide_legend(override.aes =
list(linetype = c("blank", "solid"),
shape = c(16, NA)))) +
theme_bw()
Mygraph
This graph looks pretty good:
But check out what happens to the "Type of item" bit when I try to specify the order:
Mygraph +
guides(alpha = guide_legend(order = 1),
linetype = guide_legend(order = 2),
color = guide_legend(order = 3))
Why do my specified aesthetics go away? How can I both specify what that part of the legend should look like and also specify that the order of the three parts of the legend should be 1. alpha, 2. linetype, and then 3. color?
You were attempting to override aesthetics for alpha in two places (ie guides() and scale_alpha...()), and ggplot was choosing to just interpret one of them. I suggest including your shape override with your legend order override, like this:
library(ggplot2)
ggplot(DF1, aes(x = X, y = Y, color = Fruit)) +
geom_point() +
geom_line(data = DF2, aes(x = X, y = Y, linetype = Cat), inherit.aes = F) +
labs(color = NULL, linetype = NULL) +
geom_point(data = Empty, aes(x = X, y = Y, alpha = Type), inherit.aes = F) +
geom_line(data = Empty, aes(x = X, y = Y, alpha = Type), inherit.aes = F) +
scale_alpha_manual(name = "Type of item", values = c(1, 1), breaks = c("Fruit", "Cat")) +
guides(alpha = guide_legend(order = 1,
override.aes=list(linetype = c("blank", "solid"),
shape = c(16,NA))),
linetype = guide_legend(order = 2),
color = guide_legend(order = 3)) +
theme_bw()
data:
DF1 <- data.frame(X = 1:10,
Y = c(1:10*0.5, 1:10*0.25),
Fruit = rep(c("mango", "kiwi"), each = 10))
DF2 <- data.frame(X = 1:10,
Y = c(1:10*2, 1:10*4),
Cat = rep(c("tabby", "calico"), each = 10))
Empty <- data.frame(X = mean(DF1$X),
Y = as.numeric(NA),
Type = c("Cat", "Fruit"))
Related
I have a ggplot with two y-axes by the sec.axis command, and I've been struggling with handling legends in these situations.
The code:
library(ggplot2)
library(ggrepel)
df <- data.frame(day = as.character(seq(from = 1, to = 100, by = 1)),
total = rbinom(n=100,30,0.5),
prop = runif(100))
df <- df %>% arrange(df, by = day)
df$`percentage` <- label_percent(accuracy = 0.01)(df$prop)
ggplot(data = df,
aes(x = day, y = total)) +
geom_bar(aes(x = day, y = total), stat = "identity", fill = "lightgreen", width = 0.35) +
geom_line(data = df,
aes(x = day, y = (prop)*15, group = 1, color = prop),
color = "red", size = 1,inherit.aes = TRUE) +
scale_y_continuous(
labels = function(x) format(x, scientific = FALSE),
#breaks = seq(from = 0, to = 10000000,by = 100000),
sec.axis = sec_axis(trans = ~./15,
name = "Secondary axis",
breaks = seq(from = 0, to = 10, by = 0.1),
scales::percent))+
theme(axis.text.x = element_text(angle = 90, vjust = 0.5))+
geom_label_repel(data=df[nrow(df),],
aes(x = day,
y = prop*15,
label = round(prop*100,2)),
color = 'red',
nudge_x = 2,
segment.alpha = 0.5) +
scale_x_discrete(expand = expansion(add = c(0, 7)))
And I wanted to simply have the legend, instead of having the axis description, like this:
I know it seems reasonably easy to obtain, but given the fact that I don’t have any groups, I either: can't plot any legend what so ever; or I get plotted two squares (when I wanted the legend to consist of a line, with the geom_line color and a square with the geom_bar color).
With the code #divibisan provided, I get the following output:
Final update:
I finally found the solution. I still have no idea how I got a different output from what #divibisan posted, but here goes what worked for me:
library(dplyr)
library(ggplot2)
library(ggrepel)
df <- data.frame(day = as.character(seq(from = 1, to = 100, by = 1)),
total = rbinom(n=100,30,0.5),
prop = runif(100))
df <- df %>% arrange(df, by = day)
df$`percentage` <- scales::label_percent(accuracy = 0.01)(df$prop)
ggplot(data = df,
aes(x = day, y = total)) +
geom_bar(aes(x = day, y = total, fill = "Total"), stat = "identity", width = 0.35) +
geom_line(data = df,
aes(x = day, y = (prop)*15, group = 1, color = 'Percentage'), size = 1,inherit.aes = TRUE) +
scale_y_continuous(
labels = function(x) format(x, scientific = FALSE),
#breaks = seq(from = 0, to = 10000000,by = 100000),
sec.axis = sec_axis(trans = ~./15,
name = "Secondary axis",
breaks = seq(from = 0, to = 10, by = 0.1),
scales::percent))+
theme(axis.text.x = element_text(angle = 90, vjust = 0.5))+
geom_label_repel(data=df[nrow(df),],
aes(x = day,
y = prop*15,
label = round(prop*100,2)),
color = 'red',
nudge_x = 2,
segment.alpha = 0.5) +
scale_x_discrete(expand = expansion(add = c(0, 7))) +
scale_fill_manual(values=c('Total' = 'lightgreen'), drop=TRUE, name='') +
scale_color_manual(values=c('Percentage' = "red"), drop=TRUE, name='') +
theme(legend.title = element_blank())
You just need to set the color/fill with a value in the aes, then use a scale function to set the color and create a legend. Here, we move the color= and fill= values from the bar and line into the aes. Then we add scale_fill/color_manual functions that set the color based on those names:
library(dplyr)
library(ggplot2)
library(ggrepel)
df <- data.frame(day = as.character(seq(from = 1, to = 100, by = 1)),
total = rbinom(n=100,30,0.5),
prop = runif(100))
df <- df %>% arrange(df, by = day)
df$`percentage` <- scales::label_percent(accuracy = 0.01)(df$prop)
ggplot(data = df,
aes(x = day, y = total)) +
geom_bar(aes(x = day, y = total, fill = "Total"), stat = "identity", width = 0.35) +
geom_line(data = df,
aes(x = day, y = (prop)*15, group = 1, color = 'Percentage'), size = 1,inherit.aes = TRUE) +
scale_y_continuous(
labels = function(x) format(x, scientific = FALSE),
#breaks = seq(from = 0, to = 10000000,by = 100000),
sec.axis = sec_axis(trans = ~./15,
name = "Secondary axis",
breaks = seq(from = 0, to = 10, by = 0.1),
scales::percent))+
theme(axis.text.x = element_text(angle = 90, vjust = 0.5))+
geom_label_repel(data=df[nrow(df),],
aes(x = day,
y = prop*15,
label = round(prop*100,2)),
color = 'red',
nudge_x = 2,
segment.alpha = 0.5) +
scale_x_discrete(expand = expansion(add = c(0, 7))) +
scale_fill_manual(values=c('Total' = 'lightgreen', 'Percentage'='red'), drop=TRUE, name='') +
scale_color_manual(values=c('Total' = 'lightgreen', 'Percentage'='red'), drop=TRUE, name='')
If, for some reason, the drop argument isn't working and both colors show up in both scales, there's really no reason to include them in the scale if they're not expected to be there. Just only include the colors in the scale that are desired:
scale_fill_manual(values=c('Total' = 'lightgreen'), drop=TRUE, name='') +
scale_color_manual(values=c('Percentage'='red'), drop=TRUE, name='')
I want to create a graph where I can change the line size for each line c(1,2,3) and the alpha values for each line c(0.5,0.6,0.7). I tried to use scale_size_manual but it didn't make any difference. Any ideas on how to proceed?
var <- c("T","T","T","M","M","M","A","A","A")
val <- rnorm(12,4,5)
x <- c(1:12)
df <- data.frame(var,val,x)
ggplot(aes(x= x , y = val, color = var, group = var), data = df) +
scale_color_manual(values = c("grey","blue","black")) + geom_smooth(aes(x = x, y = val), formula = "y ~ x", method = "loess",se = FALSE, size = 1) + scale_x_continuous(breaks=seq(1, 12, 1), limits=c(1, 12)) + scale_size_manual(values = c(1,2,3))
To set the size and alpha values for your lines you have to map on aesthetics. Otherwise scale_size_manual will have no effect:
library(ggplot2)
ggplot(aes(x = x, y = val, color = var, group = var), data = df) +
scale_color_manual(values = c("grey", "blue", "black")) +
geom_smooth(aes(x = x, y = val, size = var, alpha = var), formula = "y ~ x", method = "loess", se = FALSE) +
scale_x_continuous(breaks = seq(1, 12, 1), limits = c(1, 12)) +
scale_size_manual(values = c(1, 2, 3)) +
scale_alpha_manual(values = c(.5, .6, .7))
Trying to assing each variable colour by creating my own colour palette, but some of the colours get mixed up. Any ideas on how I should fix this?
cor.partidos <- c(
`ps` = "#f71b75",
`psd` = "#ef6438",
`pcp-pev` = "#ff001d",
`pan` = "#71af64",
`outros` = "#f71b75",
`nulos` = "#565557",
`brancos` = "#aaa8ad",
`l` = "#f71b75",
`il` = "#f71b75",
`ch` = "#393195",
`cds-pp` = "#1192d8",
`be` = "#b40020",
`a` = "#f71b75")
#test graph
bars <- ggplot(leg19, aes(x = partido, y = votos)) +
geom_bar(stat="identity",
position="identity",
fill = cor.partidos) +
geom_hline(yintercept = 0, size = 1, colour="#333333") +
bbc_style() +
theme(axis.text=element_text(size=10))+
labs(subtitle = "Resultados Legislativas 2019",
ylab = "votos")
update with a mwe
It will work if the variables in the pallet are in the same order as the dataframe but if you mix it around a bit it won't work. Changing it to aes(fill = cor.partidos) won't work :(
test.pallet <- c(
`pink` = "#f71b75",
`orange` = "#ef6438",
`green` = "#71af64",
`red` = "#ff001d",
`other pink` = "#f71b72")
test.datafrane <- data_frame(
name = c("pink","orange","red","green","other pink"),
value = c(1,2,3,4,5)
)
test.datafrane$value <- as.numeric(test.datafrane$value)
test.graph <- ggplot(test.datafrane, aes(x = name, y = value)) +
geom_bar(stat="identity",
position="identity",
fill = test.pallet)
test.graph
As I suggested in my comment you could achieve your result by mapping your categorical var on fill inside aes() and make use of scale_fill_manual:
test.pallet <- c(
`pink` = "#f71b75",
`orange` = "#ef6438",
`green` = "#71af64",
`red` = "#ff001d",
`other pink` = "#f71b72")
test.datafrane <- data.frame(
name = c("pink","orange","red","green","other pink"),
value = c(1,2,3,4,5)
)
test.datafrane$value <- as.numeric(test.datafrane$value)
library(ggplot2)
test.graph <- ggplot(test.datafrane, aes(x = name, y = value, fill = name)) +
geom_bar(stat="identity",
position="identity") +
scale_fill_manual(values = test.pallet)
test.graph
How can I make the line (geom_segment) appear in the legend as a separate item in its own group?
The legend should look like:
Groups
g1
g2
Info
mean
The minimal code:
data_points <- tibble(x = c(rep(1:10, 2)), y = rnorm(20), group = c(rep("g1", 10), rep("g2", 10)))
data_line <- tibble(x = 1:10, y = 0.5)
ggplot(data_points, aes(x = x, y = y, color = group)) +
geom_point() +
geom_segment(aes(x = data_line$x[1], xend = data_line$x[10], y = data_line$y[1], yend = data_line$y[10]), color = "black") +
scale_color_manual(name = "Groups", labels = c('g1', 'g2'), values = c('blue', 'red'))
Thanks in advance : )
Modified from Is it possible add legend for geom_point and geom_segment?.
library(ggplot2)
library(tibble)
data_points <- tibble(x = c(rep(1:10, 2)), y = rnorm(20), group = c(rep("g1", 10), rep("g2", 10)))
data_line <- tibble(x = 1:10, y = 0.5)
ggplot(data_points, aes(x = x, y = y, color = group)) +
geom_point() +
geom_segment(
aes(x = data_line$x[1], xend = data_line$x[10],
y = data_line$y[1], yend = data_line$y[10],
linetype = "mean"),
color = "black") +
scale_color_manual(name = "Groups", labels = c('g1', 'g2'), values = c('blue', 'red')) +
scale_linetype_manual(name = "Info", values = c("mean" = 1))
change the order of legends
ggplot(data_points, aes(x = x, y = y, color = group)) +
geom_point() +
geom_segment(
aes(x = data_line$x[1], xend = data_line$x[10],
y = data_line$y[1], yend = data_line$y[10],
linetype = "mean"),
color = "black") +
scale_color_manual(name = "Groups", labels = c('g1', 'g2'), values = c('blue', 'red')) +
scale_linetype_manual(name = "Info", values = c("mean" = 1)) +
guides(color = guide_legend(order = 2), linetype = guide_legend(order = 1))
I have a density plot with different colors per group, where I would like to add a marginal boxplot per group at the top. But the grouping is not done correctly in the boxplots, both show the same data.
set.seed(123)
library(ggplot2)
library(ggExtra)
library(data.table)
Data <- data.table(x = rnorm(100),
group = rep(c("group1", "group2"), times = c(30, 70)))
Data[group == "group1", x := x + 3]
p <-
ggplot(Data, aes(x = x, fill = group, colour = group)) +
geom_density(alpha = 0.5)
p %>% ggMarginal(type = "boxplot",
margins = "x",
size = 5,
groupColour = TRUE,
groupFill = TRUE)
UPDATE:
With geom_point it does work:
p <-
ggplot(Data, aes(x = x, y = x, fill = group, colour = group)) +
geom_point(alpha = 0.5)
p %>% ggMarginal(type = "boxplot",
margins = "x",
size = 5,
groupColour = TRUE,
groupFill = TRUE)
So, why is it not working with geom_density?
As noted in the help file for ?ggMarginal, the function expects a ggplot2 scatterplot in p.
The following would work:
p2 <- ggplot(Data, aes(x = x, fill = group, colour = group)) +
geom_point(aes(y = 0.1), alpha = 0) + # add an invisible scatterplot geom as the first layer
geom_density(alpha = 0.5)
p2 %>% ggMarginal(type = "boxplot",
margins = "x",
size = 5,
groupColour = TRUE,
groupFill = TRUE)