Shapes and Linetypes in Ggplot

merging ggplot legends with linetype, shape and color with different aes

Since you've got only 4 colours but 7 shapes, and you want to merge these in the same legend, use the same aesthetic (variable) and repeat the first four colour values in the manual override. For the linetypes, you probably don't need them in the legend as you have the shapes (and colour) to distinguish the 7 different models.

ggplot(mock.df, aes(x=vec.dat, y=value, shape=variable, color=variable, linetype=variable)) +
geom_line()+
scale_linetype_manual(values = c(rep("dotted",4),"longdash","solid","solid"))+
geom_point(size=3) +
scale_color_manual(values=c(rep("#999999",4), "#E69F00", "#56B4E9","#008f39"))+
scale_shape_manual(values=c(15,16,17,18,19,3,8))

Sample Image

How to merge color, line style and shape legends in ggplot

Here is the solution in the general case:

# Create the data frames
x <- seq(0, 10, by = 0.2)
y1 <- sin(x)
y2 <- cos(x)
y3 <- cos(x + pi / 4)
y4 <- sin(x + pi / 4)
y5 <- sin(x - pi / 4)
df1 <- data.frame(x, y = y1, Type = as.factor("sin"), Method = as.factor("method1"))
df2 <- data.frame(x, y = y2, Type = as.factor("cos"), Method = as.factor("method1"))
df3 <- data.frame(x, y = y3, Type = as.factor("cos"), Method = as.factor("method2"))
df4 <- data.frame(x, y = y4, Type = as.factor("sin"), Method = as.factor("method2"))
df5 <- data.frame(x, y = y5, Type = as.factor("sin"), Method = as.factor("method3"))

# Merge the data frames
df.merged <- rbind(df1, df2, df3, df4, df5)

# Create the interaction
type.method.interaction <- interaction(df.merged$Type, df.merged$Method)

# Compute the number of types and methods
nb.types <- nlevels(df.merged$Type)
nb.methods <- nlevels(df.merged$Method)

# Set the legend title
legend.title <- "My title"

# Initialize the plot
g <- ggplot(df.merged, aes(x,
y,
colour = type.method.interaction,
linetype = type.method.interaction,
shape = type.method.interaction)) + geom_line() + geom_point()
# Here is the magic
g <- g + scale_color_discrete(legend.title)
g <- g + scale_linetype_manual(legend.title,
values = rep(1:nb.types, nb.methods))
g <- g + scale_shape_manual(legend.title,
values = 15 + rep(1:nb.methods, each = nb.types))
# Display the plot
print(g)

The result is the following:

The solution

  • Sinus curves are drawn as solid lines and cosinus curves as dashed lines.
  • "method1" data use filled circles for the shape.
  • "method2" data use filled triangle for the shape.
  • "method3" data use filled diamonds for the shape.
  • The legend matches the curve

To summarize, the tricks are :

  • Use the Type/Method interaction for all data representations (colour, shape,
    linetype, etc.)
  • Then manually set both the curve styles and the legends styles with
    scale_xxx_manual.
  • scale_xxx_manual allows you to provide a values vector that is longer than the actual number of curves, so it's easy to compute the style vector values from the sizes of the Type and Method factors

Add a combined legend that accounts for color, shape, and linetype, while keeping the original legends

You can do this through guide_legend. Within that, you can override the default aes() specified via the other ggplot2 commands to match what you want:

p + guides(color=guide_legend(
override.aes = list(linetype=c(1,3,1,3), shape=c(16,16,17,17))))

Sample Image

ggplot lines not through shapes

You can use the "filled" version of each shape (use for example ggpubr::show_point_shapes() to see a list), so here 22, 21, 24 and 23.

fixinter <- ggplot(xx, aes(x=sample, y=fixinterbias, shape=Methods, linetype=Methods)) +
geom_line(aes(color=Methods), size = 0.75) +
geom_hline(yintercept=0, linetype="dashed", color = "black") +
scale_shape_manual(values=c(22, 21, 24, 23)) +
scale_x_continuous(name="Sample size (n)", breaks = c(1, 2, 3), label = c(20, 50, 100)) +
scale_y_continuous(name="fix-effect intercept bias") +
geom_point(aes(color=Methods, shape = Methods),
stroke = 1.0, fill = "white") +
theme_classic()

fixinter + facet_grid(tp ~. )

Sample Image

R: ggplot2 - Manually set point shape, line type, and colour according to label

You can specify the color/linetype/shape scales manually.


library("tidyverse")

df <- tibble::tribble(
~n, ~times, ~algorithms, ~shapes, ~linetypes, ~colours,
1L, 0.000271833, "algo1", "x", "solid", "blue",
11L, 0.000612195, "algo1", "x", "solid", "blue",
1L, 0.000267802, "algo2", "x", "solid", "red",
11L, 0.000644297, "algo2", "x", "solid", "red",
1L, 0.000280468, "algo3", "x", "solid", "green",
11L, 0.000816817, "algo3", "x", "solid", "green",
1L, 0.000452015, "algo4", "x", "solid", "black",
11L, 0.00271677, "algo4", "x", "solid", "black",
1L, 0.000271255, "algo5", "o", "dashed", "blue",
11L, 0.000622194, "algo5", "o", "dashed", "blue",
1L, 0.000271107, "algo6", "o", "dashed", "red",
11L, 0.000701686, "algo6", "o", "dashed", "red",
1L, 0.000267631, "algo7", "o", "dashed", "green",
11L, 0.000723341, "algo7", "o", "dashed", "green",
1L, 0.000451016, "algo8", "o", "dashed", "black",
11L, 0.00124079, "algo8", "o", "dashed", "black"
)

df %>%
ggplot(aes(
x = n, y = times,
linetype = algorithms,
shape = algorithms,
colour = algorithms
)) +
geom_line() +
# Comment out `geom_point` to check that the line type is
# as specified but is overplotted by the shape in the legend
geom_point(size = 4) +
xlab("n") +
ylab(paste0("Execution time (ms)")) +
ggtitle("asdf") +
scale_color_manual(
values = deframe(df %>% select(algorithms, colours))
) +
scale_linetype_manual(
values = deframe(df %>% select(algorithms, linetypes))
) +
scale_shape_manual(
values = deframe(df %>% select(algorithms, shapes))
) +
theme(legend.position = "bottom")

Sample Image

Created on 2019-10-30 by the reprex package (v0.3.0)

Combining linetype and color in ggplot2 legend

Here is one approach for you. I created a sample data given your data above was not enough to reproduce your graphic. I'd like to give credit to the SO users who posted answers in this question. The key trick in this post was to assign identical groups to shape and line type. Similarly, I needed to do the same for color and linetype in your case. In addition to that there was one more thing do to. I manually assigned specific colors and line types. Here, there are four levels (i.e., treatment1.AC, treatment1.AE, treatment2.EC, treatment2.EF) in the end. But I used interaction() and created eight levels. Hence, I needed to specify eight colors and line types. When I assigned a name to the legend, I realized that I need to have an identical name in both scale_color_manual() and scale_linetype_manual().

library(ggplot2)

set.seed(111)

mydf <- data.frame(year = rep(1999:2010, time = 4),
treatment.type = rep(c("AC", "AF", "EC", "EF"), each = 12),
treatment = rep(c("treatment1", "treatment2"), each = 24),
mean = c(runif(min = 0.3, max = 0.55, 12),
rep(NA, 5), runif(min = 0.3, max = 0.55, 7),
runif(min = 0.3, max = 0.55, 12),
rep(NA, 5), runif(min = 0.3, max = 0.55, 7)),
se = c(runif(min = 0.01, max = 0.03, 12),
rep(NA, 5), runif(min = 0.01, max = 0.03, 7),
runif(min = 0.01, max = 0.03, 12),
rep(NA, 5), runif(min = 0.01, max = 0.03, 7)),
stringsAsFactors = FALSE)

ggplot(data = mydf, aes(x = year, y = mean,
color = interaction(treatment, treatment.type),
linetype = interaction(treatment, treatment.type))) +
geom_point(show.legend = FALSE) +
geom_line() +
geom_errorbar(aes(ymin = mean-se, ymax = mean+se),width = 0.1, size = 0.5) +
scale_color_manual(name = "Treatment conditions", values = rep(c("blue", "blue", "red", "red"), times = 2)) +
scale_linetype_manual(name = "Treatment conditions", values = rep(c(1,2), times = 4))

Sample Image



Related Topics



Leave a reply



Submit