Home > Software design >  How to put legend names in numerical order
How to put legend names in numerical order

Time:03-03

I am working with strings that end with a number and would like to put the strings in numerical order for the figure legend.

# Example dataframe
d <- data.frame(
  SampleID = sprintf("sample_%s", rep(10:39)),
  Variable = 1:30,
  Group = append(rep("group_1", each = 15), rep("group_2", each = 15)),
  Group1 = runif(30, min=0, max=100),
  Group2 = runif(30, min=0, max=100)
)

# Character level I add to give each animal unique shape
d$Animals <- sprintf("Animal_%s",rep(c(1:10), each = 3)) 

library(ggplot2)

# Plot
ggplot(d, aes(Group1, Group2, color=Group, shape=Animals))  
  xlab(paste0("Value 1"))  
  ylab(paste0("Value 2"))   
  coord_fixed()  
  geom_point()  
  scale_shape_manual(values=c(0:10))

My current output is this enter image description here

CodePudding user response:

You can make the convert the Animal variable into an ordered and leveled factor

# Example dataframe
d <- data.frame(
  SampleID = sprintf("sample_%s", rep(10:39)),
  Variable = 1:30,
  Group = append(rep("group_1", each = 15), rep("group_2", each = 15)),
  Group1 = runif(30, min=0, max=100),
  Group2 = runif(30, min=0, max=100)
)

# Character level I add to give each animal unique shape
d$Animals <- sprintf("Animal_%s",rep(c(1:10), each = 3)) 


d <- d %>% 
  mutate(Animals = factor(Animals, 
                          levels = c( "Animal_1" , "Animal_2" , "Animal_3" , "Animal_4",  "Animal_5" ,
  "Animal_6" , "Animal_7",  "Animal_8" , "Animal_9"  ,"Animal_10"), 
  ordered = T))
library(ggplot2)

# Plot
ggplot(d, aes(Group1, Group2, color=Group, shape=Animals))  
  xlab(paste0("Value 1"))  
  ylab(paste0("Value 2"))   
  coord_fixed()  
  geom_point()  
  scale_shape_manual(values=c(0:10))

sample

CodePudding user response:

The accepted solution is not viable if the number of factors is too large as it requires manually typing the factor levels in the correct order. The other solution proposed (using unique(d$Animals) to get the levels in the correct order) also may fail if the original data is incorrectly ordered. In case someone needs a more general solution (this is a very common problem) you can use

d$Animals <- factor(sprintf("Animal_%s",rep(c(1:10), each = 3)))

d$Animals <- reorder(d$Animals,
  as.numeric(gsub("^[^_]*_(\\d ).*", "\\1", d$Animals)))

This will properly reorder the levels according to the first number found in the string regardless of being 10 or 1000 levels and the order they appear in your dataset.

CodePudding user response:

Thank you @Susan Switzer, I'll accept this answer, however I made a slight change to your original solution.

d <- data.frame(
  SampleID = sprintf("sample_%s", rep(10:39)),
  Variable = 1:30,
  Group = append(rep("group_1", each = 15), rep("group_2", each = 15)),
  Group1 = runif(30, min=0, max=100),
  Group2 = runif(30, min=0, max=100)
)


d$Animals <- sprintf("Animal_%s",rep(c(1:10), each = 3)) 


library(dplyr)

d <- d %>% 
  mutate(Animals = factor(Animals, 
                          levels = unique(d$Animals), 
                          ordered = T))

library(ggplot2)

ggplot(d, aes(Group1, Group2, color=Group, shape=Animals))  
  xlab(paste0("Value 1"))  
  ylab(paste0("Value 2"))   
  coord_fixed()  
  geom_point()  
  scale_shape_manual(values=c(0:10))

enter image description here

  • Related