rplotassignsignificance

rcompanion::cldList() I am trying to re order CldList output to match figures order, and start with the group that my figure starts with


I want the re order my tukeyHSD results comparison table, so that rcompanion::cldList() [@SalMangiafico] assigns letters in a specific order.

I am Looking at spicule (Sponge skeleton) variation between a heavily nested model. I have produced a plot for this model :

Bar plot depicting spicule measurements across the three study sites, with season and height nested within each site. The top, middle, and bottom panels represent length, square root area, and width, respectively. Shared letters denote non-significant differences within each spicule measure.

I am wanting CldList to assign letters in the following order to match my plot and have first bar staring with a :

desired_order <- c(
  "Summer:Beggers:Mid", "Summer:Beggers:Low",
  "Winter:Beggers:Mid", "Winter:Beggers:Low",
  "Summer:Looe:Mid", "Summer:Looe:Low", 
  "Winter:Looe:Mid", "Winter:Looe:Low",
  "Summer:Noss:Mid", "Summer:Noss:Low",
  "Winter:Noss:Mid", "Winter:Noss:Low"
)"

Here is my TukeyHSD results in a comparison and p-value table ready for cldlist() which in my code is referred to as length_df:

edit : Had to remove some stuff to fit character limit: TukeyHSD output is given below as 'length_tukey2'

I've tried many different methods, and none worked.

  1. Attempt 1:
# Define the desired order of comparisons
desired_order <- c(
  "Summer:Beggers:Mid", "Summer:Beggers:Low",
  "Winter:Beggers:Mid", "Winter:Beggers:Low",
  "Summer:Looe:Mid", "Summer:Looe:Low", 
  "Winter:Looe:Mid", "Winter:Looe:Low",
  "Summer:Noss:Mid", "Summer:Noss:Low",
  "Winter:Noss:Mid", "Winter:Noss:Low"
)

# Create the data frame with the 'Comparison' column ordered according to the desired order
length_df <- data.frame(
  Comparison = names(length_tukey_results[, "p adj"]),
  P.adj = as.vector(length_tukey_results[, "p adj"])
)

# Reorder the data frame based on the desired order
length_df$Comparison <- factor(length_df$Comparison, levels = desired_order)
length_df <- length_df[order(length_df$Comparison), ]
  1. Attempt 2: I thought maybe I had to match the comparison row and set that in a specific order.
length_df$Comparison
# Define the exact desired order of comparisons
desired_order <- c(
  "Summer.Beggers.Mid-Summer.Beggers.Low",
  "Summer.Beggers.Mid-Winter.Beggers.Low", 
  "Summer.Beggers.Mid-Summer.Looe.Mid",
  "Summer.Beggers.Mid-Winter.Looe.Mid", 
  "Summer.Beggers.Mid-Summer.Noss.Mid",
  "Summer.Beggers.Mid-Winter.Noss.Mid", 
  "Summer.Beggers.Mid-Summer.Looe.Low",
  "Summer.Beggers.Mid-Winter.Looe.Low", 
  "Summer.Beggers.Mid-Summer.Noss.Low",
  "Summer.Beggers.Mid-Winter.Noss.Low", 
  "Summer.Beggers.Low-Summer.Beggers.Mid",
  "Summer.Beggers.Low-Winter.Beggers.Mid", 
  "Summer.Beggers.Low-Summer.Looe.Mid",
  "Summer.Beggers.Low-Winter.Looe.Mid", 
  "Summer.Beggers.Low-Summer.Noss.Mid",
  "Summer.Beggers.Low-Winter.Noss.Mid", 
  "Summer.Beggers.Low-Summer.Looe.Low",
  "Summer.Beggers.Low-Winter.Looe.Low", 
  "Summer.Beggers.Low-Summer.Noss.Low",
  "Summer.Beggers.Low-Winter.Noss.Low", 
  "Winter.Beggers.Mid-Summer.Beggers.Mid",
  "Winter.Beggers.Mid-Summer.Looe.Mid", 
  "Winter.Beggers.Mid-Winter.Looe.Mid",
  "Winter.Beggers.Mid-Summer.Noss.Mid", 
  "Winter.Beggers.Mid-Winter.Noss.Mid",
  "Winter.Beggers.Mid-Summer.Looe.Low", 
  "Winter.Beggers.Mid-Winter.Looe.Low",
  "Winter.Beggers.Mid-Summer.Noss.Low", 
  "Winter.Beggers.Mid-Winter.Noss.Low",
  "Winter.Beggers.Low-Summer.Beggers.Mid",
  "Winter.Beggers.Low-Winter.Beggers.Mid",
  "Winter.Beggers.Low-Summer.Looe.Mid",
  "Winter.Beggers.Low-Winter.Looe.Mid",
  "Winter.Beggers.Low-Summer.Noss.Mid",
  "Winter.Beggers.Low-Winter.Noss.Mid",
  "Winter.Beggers.Low-Summer.Beggers.Low",
  "Summer.Looe.Mid-Summer.Beggers.Mid", 
  "Summer.Looe.Mid-Winter.Beggers.Mid",
  "Summer.Looe.Mid-Summer.Looe.Mid", 
  "Summer.Looe.Mid-Winter.Looe.Mid",
  "Summer.Looe.Mid-Summer.Noss.Mid", 
  "Summer.Looe.Mid-Winter.Noss.Mid",
  "Summer.Looe.Mid-Summer.Looe.Low", 
  "Summer.Looe.Mid-Winter.Looe.Low",
  "Summer.Looe.Mid-Summer.Noss.Low", 
  "Summer.Looe.Mid-Winter.Noss.Low",
  "Summer.Looe.Low-Summer.Beggers.Mid", 
  "Summer.Looe.Low-Winter.Beggers.Mid",
  "Summer.Looe.Low-Summer.Looe.Mid", 
  "Summer.Looe.Low-Winter.Looe.Mid",
  "Summer.Looe.Low-Summer.Noss.Mid", 
  "Summer.Looe.Low-Winter.Noss.Mid",
  "Summer.Looe.Low-Summer.Looe.Low", 
  "Summer.Looe.Low-Winter.Looe.Low",
  "Summer.Looe.Low-Summer.Noss.Low", 
  "Summer.Looe.Low-Winter.Noss.Low",
  "Summer.Looe.Low-Summer.Beggers.Low",
  "Summer.Looe.Low-Winter.Beggers.Low",
  "Winter.Looe.Mid-Summer.Beggers.Mid", 
  "Winter.Looe.Mid-Summer.Looe.Mid",
  "Winter.Looe.Mid-Winter.Looe.Mid", 
  "Winter.Looe.Mid-Summer.Noss.Mid",
  "Winter.Looe.Mid-Winter.Noss.Mid", 
  "Winter.Looe.Mid-Summer.Looe.Low",
  "Winter.Looe.Mid-Winter.Looe.Low", 
  "Winter.Looe.Mid-Summer.Noss.Low",
  "Winter.Looe.Mid-Winter.Noss.Low",
  "Winter.Looe.Mid-Winter.Beggers.Mid",
  "Winter.Looe.Low-Summer.Beggers.Mid",
  "Winter.Looe.Low-Summer.Looe.Mid", 
  "Winter.Looe.Low-Winter.Looe.Mid",
  "Winter.Looe.Low-Summer.Noss.Mid", 
  "Winter.Looe.Low-Winter.Noss.Mid",
  "Winter.Looe.Low-Summer.Looe.Low", 
  "Winter.Looe.Low-Winter.Looe.Low",
  "Winter.Looe.Low-Summer.Noss.Low", 
  "Winter.Looe.Low-Winter.Noss.Low",
  "Winter.Looe.Low-Summer.Beggers.Low",
  "Winter.Looe.Low-Winter.Beggers.Mid",
  "Winter.Looe.Low-Winter.Beggers.Low",
  "Summer.Noss.Mid-Summer.Beggers.Mid", 
  "Summer.Noss.Mid-Winter.Beggers.Mid",
  "Summer.Noss.Mid-Summer.Looe.Mid", 
  "Summer.Noss.Mid-Winter.Looe.Mid",
  "Summer.Noss.Mid-Summer.Noss.Mid", 
  "Summer.Noss.Mid-Winter.Noss.Mid",
  "Summer.Noss.Mid-Summer.Looe.Low", 
  "Summer.Noss.Mid-Winter.Looe.Low",
  "Summer.Noss.Mid-Summer.Noss.Low", 
  "Summer.Noss.Mid-Winter.Noss.Low",
  "Summer.Noss.Low-Summer.Beggers.Mid", 
  "Summer.Noss.Low-Winter.Beggers.Mid",
  "Summer.Noss.Low-Summer.Looe.Mid", 
  "Summer.Noss.Low-Winter.Looe.Mid",
  "Summer.Noss.Low-Summer.Noss.Mid", 
  "Summer.Noss.Low-Winter.Noss.Mid",
  "Summer.Noss.Low-Summer.Looe.Low", 
  "Summer.Noss.Low-Winter.Looe.Low",
  "Summer.Noss.Low-Summer.Noss.Low", 
  "Summer.Noss.Low-Winter.Noss.Low",
  "Summer.Noss.Low-Summer.Beggers.Low",
  "Summer.Noss.Low-Winter.Beggers.Low",
  "Winter.Noss.Mid-Summer.Beggers.Mid", 
  "Winter.Noss.Mid-Summer.Looe.Mid",
  "Winter.Noss.Mid-Winter.Looe.Mid", 
  "Winter.Noss.Mid-Summer.Noss.Mid",
  "Winter.Noss.Mid-Winter.Noss.Mid", 
  "Winter.Noss.Mid-Summer.Looe.Low",
  "Winter.Noss.Mid-Winter.Looe.Low", 
  "Winter.Noss.Mid-Summer.Noss.Low",
  "Winter.Noss.Mid-Winter.Noss.Low",
  "Winter.Noss.Mid-Winter.Beggers.Mid",
  "Winter.Noss.Low-Summer.Beggers.Mid",
  "Winter.Noss.Low-Summer.Looe.Mid", 
  "Winter.Noss.Low-Winter.Looe.Mid",
  "Winter.Noss.Low-Summer.Noss.Mid", 
  "Winter.Noss.Low-Winter.Noss.Mid",
  "Winter.Noss.Low-Summer.Looe.Low", 
  "Winter.Noss.Low-Winter.Looe.Low",
  "Winter.Noss.Low-Summer.Noss.Low", 
  "Winter.Noss.Low-Winter.Noss.Low",
  "Winter.Noss.Low-Winter.Beggers.Mid",
  "Winter.Noss.Low-Summer.Beggers.Low",
  "Winter.Noss.Low-Winter.Beggers.Low"
)

length_df$Comparison[!length_df$Comparison %in% desired_order]
# character(0)

desired_order
# Reorder the rows of 'length_df' based on the 'desired_order'
length_df$Comparison <- factor(length_df$Comparison, levels = desired_order)
length_df <- length_df[order(length_df$Comparison),]

# View the result
print(length_df)
length_df <- read.table(text = "'Row' 'Comparison' 'P.adj'
1 'Summer.Beggers.Low-Summer.Beggers.Mid' 5.807083e-04
2 'Summer.Beggers.Low-Winter.Beggers.Mid' 1.724772e-06
3 'Summer.Beggers.Low-Summer.Looe.Mid' 4.744247e-09
4 'Summer.Beggers.Low-Winter.Looe.Mid' 4.744245e-09
5 'Summer.Beggers.Low-Summer.Noss.Mid' 4.744612e-09
6 'Summer.Beggers.Low-Winter.Noss.Mid' 4.444223e-06
7 'Winter.Beggers.Mid-Summer.Beggers.Mid' 4.744253e-09
8 'Winter.Beggers.Low-Summer.Beggers.Mid' 4.744306e-09
9 'Winter.Beggers.Low-Winter.Beggers.Mid' 7.580746e-01
10 'Summer.Looe.Mid-Summer.Beggers.Mid' 1.138199e-07
11 'Summer.Looe.Mid-Winter.Beggers.Mid' 4.744133e-09
12 'Summer.Looe.Low-Summer.Beggers.Mid' 4.811983e-09
13 'Summer.Looe.Low-Winter.Beggers.Mid' 4.744133e-09
14 'Summer.Looe.Low-Summer.Looe.Mid' 9.916068e-01
15 'Summer.Looe.Low-Winter.Looe.Mid' 7.486876e-01
16 'Summer.Looe.Low-Summer.Noss.Mid' 2.461065e-03
17 'Summer.Looe.Low-Winter.Noss.Mid' 7.037123e-09
18 'Summer.Looe.Low-Summer.Beggers.Low' 4.744133e-09
19 'Winter.Looe.Mid-Summer.Beggers.Mid' 1.808862e-06
20 'Winter.Looe.Mid-Summer.Looe.Mid' 9.999087e-01
21 'Winter.Looe.Mid-Winter.Beggers.Mid' 4.744133e-09
22 'Winter.Looe.Low-Summer.Beggers.Mid' 1.576504e-02
23 'Winter.Looe.Low-Summer.Looe.Mid' 1.664206e-01
24 'Winter.Looe.Low-Winter.Looe.Mid' 5.513244e-01
25 'Winter.Looe.Low-Summer.Noss.Mid' 1.000000e+00
26 'Winter.Looe.Low-Winter.Noss.Mid' 1.311895e-01
27 'Winter.Looe.Low-Summer.Looe.Low' 3.044077e-03
28 'Winter.Looe.Low-Summer.Beggers.Low' 4.744259e-09
29 'Winter.Looe.Low-Winter.Beggers.Mid' 4.744133e-09
30 'Winter.Looe.Low-Winter.Beggers.Low' 4.744133e-09
31 'Summer.Noss.Mid-Summer.Beggers.Mid' 5.481544e-02
32 'Summer.Noss.Mid-Winter.Beggers.Mid' 4.744133e-09
33 'Summer.Noss.Mid-Summer.Looe.Mid' 1.275696e-01
34 'Summer.Noss.Mid-Winter.Looe.Mid' 4.524766e-01
35 'Summer.Noss.Low-Summer.Beggers.Mid' 9.104882e-04
36 'Summer.Noss.Low-Winter.Beggers.Mid' 4.744133e-09
37 'Summer.Noss.Low-Summer.Looe.Mid' 7.513767e-01
38 'Summer.Noss.Low-Winter.Looe.Mid' 9.841118e-01
39 'Summer.Noss.Low-Summer.Noss.Mid' 9.952838e-01
40 'Summer.Noss.Low-Winter.Noss.Mid' 1.206607e-02
41 'Summer.Noss.Low-Summer.Looe.Low' 8.300121e-02
42 'Summer.Noss.Low-Winter.Looe.Low' 9.992360e-01
43 'Summer.Noss.Low-Summer.Beggers.Low' 4.744227e-09
44 'Summer.Noss.Low-Winter.Beggers.Low' 4.744133e-09
45 'Winter.Noss.Mid-Summer.Beggers.Mid' 9.997435e-01
46 'Winter.Noss.Mid-Summer.Looe.Mid' 2.844608e-06
47 'Winter.Noss.Mid-Winter.Looe.Mid' 4.297392e-05
48 'Winter.Noss.Mid-Summer.Noss.Mid' 3.046563e-01
49 'Winter.Noss.Mid-Winter.Beggers.Mid' 4.744143e-09
50 'Winter.Noss.Low-Summer.Beggers.Mid' 1.602939e-01
51 'Winter.Noss.Low-Summer.Looe.Mid' 4.744255e-09
52 'Winter.Noss.Low-Winter.Looe.Mid' 4.744219e-09
53 'Winter.Noss.Low-Summer.Noss.Mid' 1.551057e-08
54 'Winter.Noss.Low-Winter.Noss.Mid' 7.554644e-03
55 'Winter.Noss.Low-Summer.Looe.Low' 4.744247e-09
56 'Winter.Noss.Low-Winter.Looe.Low' 4.974489e-09
57 'Winter.Noss.Low-Summer.Noss.Low' 4.746061e-09
58 'Winter.Noss.Low-Winter.Beggers.Mid' 4.744843e-09
59 'Winter.Noss.Low-Summer.Beggers.Low' 8.016093e-01
60 'Winter.Noss.Low-Winter.Beggers.Low' 7.351187e-07", header = TRUE, sep = " ")

After each of these data frame mutations, I use the following code to run CldList. For attempt 2, it follows the order, but does not start with Summer.Beggers.Mid as it is always the second component in any comparison.

# Use cldList to get compact letter display
length_cld <- cldList(
  p.value = length_df$P.adj,
  comparison = length_df$Comparison,
  threshold = 0.05
)
# View results
print(length_cld)

# Attempt 2
> print(length_cld)
#                Group Letter MonoLetter
#1  Summer.Beggers.Low      a    a      
#2  Winter.Beggers.Mid      b     b     
#3  Winter.Beggers.Low      b     b     
#4     Summer.Looe.Mid     cd      cd   
#5     Summer.Looe.Low      c      c    
#6     Winter.Looe.Mid     cd      cd   
#7     Winter.Looe.Low     de       de  
#8     Summer.Noss.Mid    def       def 
#9     Summer.Noss.Low     cd      cd   
#10    Winter.Noss.Mid     ef        ef 
#11    Winter.Noss.Low     ag    a     g
#12 Summer.Beggers.Mid     fg         fg

So overall:

  1. CldList works normally without setting a desired order.

  2. I want it in a specific order to match the figure order attached, so that the first columns / bar starts with a, and not EG (After edit, figure does not match new CLDlist, now is fg). It is starting with Summer.Beggers.Low as this is the first component in most comparisons with it.

  3. Is this then to do with the way TukeyHSD formats its results? If so, is there a way to alter the TukeyHSD code to have Summer.Beggers.Mid as a first component in pair-wise comparisons?

  4. Attempt 3 : I went though my length_df and manually flipped all comparisons with Summer.Beggers.Mid to have it as the first component in the comparison. But it completely changes the compact letter display: Interestingly, Winter.Beggers.Low is now assigned 'cefgh', when previously it was a single letter (b) different from all other comparisons except Winter.beggers.Mid

I am unsure why as the p-values should be the exact same even if the comparisons are flipped? There must be something I have written wrong or the output of TukeyHSD is this way for a reason? But all the same comparions are present in length_df and my new length_df_ordered2 with Summer.Beggers.Mid as the first component in its comparisons.

length_df_ordered2 <- read.table(text = "
Row Comparison P.adj
1 'Summer.Beggers.Mid-Summer.Beggers.Low' 5.807083e-04
8 'Summer.Beggers.Mid-Winter.Beggers.Low' 4.744306e-09
10 'Summer.Beggers.Mid-Summer.Looe.Mid' 1.138199e-07
19 'Summer.Beggers.Mid-Winter.Looe.Mid' 1.808862e-06
31 'Summer.Beggers.Mid-Summer.Noss.Mid' 5.481544e-02
45 'Summer.Beggers.Mid-Winter.Noss.Mid' 9.997435e-01
12 'Summer.Beggers.Mid-Summer.Looe.Low' 4.811983e-09
22 'Summer.Beggers.Mid-Winter.Looe.Low' 1.576504e-02
35 'Summer.Beggers.Mid-Summer.Noss.Low' 9.104882e-04
50 'Summer.Beggers.Mid-Winter.Noss.Low' 1.602939e-01
2 'Summer.Beggers.Low-Winter.Beggers.Mid' 1.724772e-06
3 'Summer.Beggers.Low-Summer.Looe.Mid' 4.744247e-09
4 'Summer.Beggers.Low-Winter.Looe.Mid' 4.744245e-09
5 'Summer.Beggers.Low-Summer.Noss.Mid' 4.744612e-09
6 'Summer.Beggers.Low-Winter.Noss.Mid' 4.444223e-06
7 'Winter.Beggers.Mid-Summer.Beggers.Mid' 4.744253e-09
9 'Winter.Beggers.Low-Winter.Beggers.Mid' 7.580746e-01
11 'Summer.Looe.Mid-Winter.Beggers.Mid' 4.744133e-09
13 'Summer.Looe.Low-Winter.Beggers.Mid' 4.744133e-09
14 'Summer.Looe.Low-Summer.Looe.Mid' 9.916068e-01
15 'Summer.Looe.Low-Winter.Looe.Mid' 7.486876e-01
16 'Summer.Looe.Low-Summer.Noss.Mid' 2.461065e-03
17 'Summer.Looe.Low-Winter.Noss.Mid' 7.037123e-09
18 'Summer.Looe.Low-Summer.Beggers.Low' 4.744133e-09
20 'Winter.Looe.Mid-Summer.Looe.Mid' 9.999087e-01
21 'Winter.Looe.Mid-Winter.Beggers.Mid' 4.744133e-09
23 'Winter.Looe.Low-Summer.Looe.Mid' 1.664206e-01
24 'Winter.Looe.Low-Winter.Looe.Mid' 5.513244e-01
25 'Winter.Looe.Low-Summer.Noss.Mid' 1.000000e+00
26 'Winter.Looe.Low-Winter.Noss.Mid' 1.311895e-01
27 'Winter.Looe.Low-Summer.Looe.Low' 3.044077e-03
28 'Winter.Looe.Low-Summer.Beggers.Low' 4.744259e-09
29 'Winter.Looe.Low-Winter.Beggers.Mid' 4.744133e-09
30 'Winter.Looe.Low-Winter.Beggers.Low' 4.744133e-09
32 'Summer.Noss.Mid-Winter.Beggers.Mid' 4.744133e-09
33 'Summer.Noss.Mid-Summer.Looe.Mid' 1.275696e-01
34 'Summer.Noss.Mid-Winter.Looe.Mid' 4.524766e-01
36 'Summer.Noss.Low-Winter.Beggers.Mid' 4.744133e-09
37 'Summer.Noss.Low-Summer.Looe.Mid' 7.513767e-01
38 'Summer.Noss.Low-Winter.Looe.Mid' 9.841118e-01
39 'Summer.Noss.Low-Summer.Noss.Mid' 9.952838e-01
40 'Summer.Noss.Low-Winter.Noss.Mid' 1.206607e-02
41 'Summer.Noss.Low-Summer.Looe.Low' 8.300121e-02
42 'Summer.Noss.Low-Winter.Looe.Low' 9.992360e-01
43 'Summer.Noss.Low-Summer.Beggers.Low' 4.744227e-09
44 'Summer.Noss.Low-Winter.Beggers.Low' 4.744133e-09
46 'Winter.Noss.Mid-Summer.Looe.Mid' 2.844608e-06
47 'Winter.Noss.Mid-Winter.Looe.Mid' 4.297392e-05
48 'Winter.Noss.Mid-Summer.Noss.Mid' 3.046563e-01
49 'Winter.Noss.Mid-Winter.Beggers.Mid' 4.744143e-09
51 'Winter.Noss.Low-Summer.Looe.Mid' 4.744255e-09
52 'Winter.Noss.Low-Winter.Looe.Mid' 4.744219e-09
53 'Winter.Noss.Low-Summer.Noss.Mid' 1.551057e-08
54 'Winter.Noss.Low-Winter.Noss.Mid' 7.554644e-03
55 'Winter.Noss.Low-Summer.Looe.Low' 4.744247e-09
56 'Winter.Noss.Low-Winter.Looe.Low' 4.974489e-09
57 'Winter.Noss.Low-Summer.Noss.Low' 4.746061e-09
58 'Winter.Noss.Low-Winter.Beggers.Mid' 4.744843e-09
59 'Winter.Noss.Low-Summer.Beggers.Low' 8.016093e-01
60 'Winter.Noss.Low-Winter.Beggers.Low' 7.351187e-07
", header = TRUE)

# Check for missing comaprions #
length_df_ordered2$Comparison[!length_df_ordered2$Comparison %in% length_df]
# character(0)

# Use cldList to get compact letter display
length_cld_ordered2 <- cldList(
  p.value = length_df_ordered2$P.adj,
  comparison = length_df_ordered2$Comparison,
  threshold = 0.05
)
# View results

print(length_cld_ordered2)
#      Group           Letter  MonoLetter
#1  Summer.Beggers.Mid     ab ab         
#2  Summer.Beggers.Low     cd   cd       
#3  Winter.Beggers.Mid      e     e      
#4  Winter.Beggers.Low  cefgh   c efgh   
#5     Summer.Looe.Mid   fgij      fg ij 
#6     Summer.Looe.Low     fi      f  i  
#7     Winter.Looe.Mid   fgij      fg ij 
#8     Winter.Looe.Low     jk          jk
#9     Summer.Noss.Mid  aghjk a     gh jk
#10    Summer.Noss.Low     ij         ij 
#11    Winter.Noss.Mid    ahk a      h  k
#12    Winter.Noss.Low     bd  b d       

Hopefully this can be worked around to make plot more aesthetic and easier to follow.

If in need of more info / context / data just comment :)

Many thanks for all responses.

CONTEXT FOR CORRECT ANSWER : Edit : Below table has a 'Comparison' column added, and 'p adj' replaced with p_adj, as my previous syntax was incorrect.

length_Tukey <- TukeyHSD(length.mod.max)
length_Tukey

length_tukey2 <- read.table(text = "
Comparion diff         lwr          upr     p_adj
'Winter:Beggers:Mid-Summer:Beggers:Mid'  29.4223913  19.8928280  38.95195464 0.0000000
'Summer:Looe:Mid-Summer:Beggers:Mid'    -17.0816085 -26.3374620  -7.82575506 0.0000001
'Winter:Looe:Mid-Summer:Beggers:Mid'    -15.2041608 -24.1435742  -6.26474731 0.0000018
'Summer:Noss:Mid-Summer:Beggers:Mid'     -9.1104143 -18.3054013   0.08457279 0.0548154
'Winter:Noss:Mid-Summer:Beggers:Mid'     -2.2282797 -11.4180417   6.96148231 0.9997435
'Summer:Beggers:Low-Summer:Beggers:Mid'  13.0708662   3.4300630  22.71166931 0.0005807
'Winter:Beggers:Low-Summer:Beggers:Mid'  23.8704968  14.2899835  33.45101004 0.0000000
'Summer:Looe:Low-Summer:Beggers:Mid'    -20.2690529 -29.5565237 -10.98158210 0.0000000
'Winter:Looe:Low-Summer:Beggers:Mid'     -9.7459188 -18.5546802  -0.93715738 0.0157650
'Summer:Noss:Low-Summer:Beggers:Mid'    -11.9838481 -21.0283902  -2.93930611 0.0009105
'Winter:Noss:Low-Summer:Beggers:Mid'      7.9324954  -1.1718230  17.03681388 0.1602939
'Summer:Looe:Mid-Winter:Beggers:Mid'    -46.5039998 -55.7168884 -37.29111130 0.0000000
'Winter:Looe:Mid-Winter:Beggers:Mid'    -44.6265521 -53.5214723 -35.73163191 0.0000000
'Summer:Noss:Mid-Winter:Beggers:Mid'    -38.5328056 -47.6845420 -29.38106919 0.0000000
'Winter:Noss:Mid-Winter:Beggers:Mid'    -31.6506710 -40.7971576 -22.50418438 0.0000000
'Summer:Beggers:Low-Winter:Beggers:Mid' -16.3515252 -25.9510865  -6.75196384 0.0000017
'Winter:Beggers:Low-Winter:Beggers:Mid'  -5.5518946 -15.0909053   3.98711623 0.7580746
'Summer:Looe:Low-Winter:Beggers:Mid'    -49.6914442 -58.9360971 -40.44679139 0.0000000
'Winter:Looe:Low-Winter:Beggers:Mid'    -39.1683101 -47.9319149 -30.40470528 0.0000000
'Summer:Noss:Low-Winter:Beggers:Mid'    -41.4062395 -50.4068079 -32.40567100 0.0000000
'Winter:Noss:Low-Winter:Beggers:Mid'    -21.4898959 -30.5505309 -12.42926090 0.0000000
'Winter:Looe:Mid-Summer:Looe:Mid'         1.8774477  -6.7235900  10.47848551 0.9999087
'Summer:Noss:Mid-Summer:Looe:Mid'         7.9711942  -0.8951762  16.83756468 0.1275696
'Winter:Noss:Mid-Summer:Looe:Mid'        14.8533288   5.9923772  23.71428043 0.0000028
'Summer:Beggers:Low-Summer:Looe:Mid'     30.1524747  20.8245691  39.48038029 0.0000000
'Winter:Beggers:Low-Summer:Looe:Mid'     40.9521053  31.6865253  50.21768526 0.0000000
'Summer:Looe:Low-Summer:Looe:Mid'        -3.1874444 -12.1496903   5.77480151 0.9916068
'Winter:Looe:Low-Summer:Looe:Mid'         7.3356897  -1.1294751  15.80085454 0.1664206
'Summer:Noss:Low-Summer:Looe:Mid'         5.0977604  -3.6124910  13.80801170 0.7513767
'Winter:Noss:Low-Summer:Looe:Mid'        25.0141039  16.2417979  33.78640992 0.0000000
'Summer:Noss:Mid-Winter:Looe:Mid'         6.0937465  -2.4417567  14.62924969 0.4524766
'Winter:Noss:Mid-Winter:Looe:Mid'        12.9758811   4.4460069  21.50575525 0.0000430
'Summer:Beggers:Low-Winter:Looe:Mid'     28.2750269  19.2610315  37.28902233 0.0000000
'Winter:Beggers:Low-Winter:Looe:Mid'     39.0746575  30.1251736  48.02414145 0.0000000
'Summer:Looe:Low-Winter:Looe:Mid'        -5.0648921 -13.6999452   3.57016094 0.7486876
'Winter:Looe:Low-Winter:Looe:Mid'         5.4582420  -2.6597199  13.57620387 0.5513244
'Summer:Noss:Low-Winter:Looe:Mid'         3.2203126  -5.1529047  11.59352994 0.9841118
'Winter:Noss:Low-Winter:Looe:Mid'        23.1366562  14.6989051  31.57440721 0.0000000
'Winter:Noss:Mid-Summer:Noss:Mid'         6.8821346  -1.9152189  15.67948801 0.3046563
'Summer:Beggers:Low-Summer:Noss:Mid'     22.1812804  12.9137680  31.44879289 0.0000000
'Winter:Beggers:Low-Summer:Noss:Mid'     32.9809110  23.7761331  42.18568895 0.0000000
'Summer:Looe:Low-Summer:Noss:Mid'       -11.1586386 -20.0580103  -2.25926699 0.0024611
'Winter:Looe:Low-Summer:Noss:Mid'        -0.6355045  -9.0340746   7.76306555 1.0000000
'Summer:Noss:Low-Summer:Noss:Mid'        -2.8734339 -11.5189785   5.77211077 0.9952838
'Winter:Noss:Low-Summer:Noss:Mid'        17.0429097   8.3348492  25.75097011 0.0000000
'ummer:Beggers:Low-Winter:Noss:Mid'     15.2991459   6.0368175  24.56147417 0.0000044
'Winter:Beggers:Low-Winter:Noss:Mid'     26.0987764  16.8992180  35.29833487 0.0000000
'Summer:Looe:Low-Winter:Noss:Mid'       -18.0407732 -26.9347461  -9.14680029 0.0000000
'Winter:Looe:Low-Winter:Noss:Mid'        -7.5176391 -15.9104883   0.87521012 0.1311895
'Summer:Noss:Low-Winter:Noss:Mid'        -9.7555684 -18.3955558  -1.11558113 0.0120661
'Winter:Noss:Low-Winter:Noss:Mid'        10.1607751   1.4582321  18.86331813 0.0075546
'Winter:Beggers:Low-Summer:Beggers:Low'  10.7996306   1.1494889  20.44977230 0.0135847
'Summer:Looe:Low-Summer:Beggers:Low'    -33.3399191 -42.6991986 -23.98063950 0.0000000
'Winter:Looe:Low-Summer:Beggers:Low'    -22.8167849 -31.7012251 -13.93234475 0.0000000
'Summer:Noss:Low-Summer:Beggers:Low'    -25.0547143 -34.1729784 -15.93645018 0.0000000
'Winter:Noss:Low-Summer:Beggers:Low'     -5.1383707 -14.3159312   4.03918965 0.8016093
'Summer:Looe:Low-Winter:Beggers:Low'    -44.1395497 -53.4367139 -34.84238539 0.0000000
'Winter:Looe:Low-Winter:Beggers:Low'    -33.6164155 -42.4353966 -24.79743448 0.0000000
'Summer:Noss:Low-Winter:Beggers:Low'    -35.8543449 -44.9088405 -26.79984933 0.0000000
'Winter:Noss:Low-Winter:Beggers:Low'    -15.9380013 -25.0522081  -6.82379462 0.0000007
'Winter:Looe:Low-Summer:Looe:Low'        10.5231341   2.0234102  19.02285801 0.0030441
'Summer:Noss:Low-Summer:Looe:Low'         8.2852048  -0.4586370  17.02904655 0.0830012
'Winter:Noss:Low-Summer:Looe:Low'        28.2015483  19.3958886  37.00720806 0.0000000
'Summer:Noss:Low-Winter:Looe:Low'        -2.2379294 -10.4715150   5.99565630 0.9992360
'Winter:Noss:Low-Winter:Looe:Low'        17.6784142   9.3792090  25.97761940 0.0000000
'Winter:Noss:Low-Summer:Noss:Low'        19.9163435  11.3672927  28.46539437 0.0000000", header = TRUE)
length.mod.max <- aov(length ~ season * site * height, data=data)
summary(length.mod.max)
length_Tukey <- TukeyHSD(length.mod.max)
length_Tukey



# Extract the Tukey results
length_tukey_results <- length_Tukey$`season:site:height`

# Convert to a data frame and make row names a new column
length_tukey_results <- as.data.frame(length_tukey_results)
length_tukey_results$Comparison <- rownames(length_tukey_results)

# move 'Comparison' to the first column
length_tukey_results <- length_tukey_results[, c(ncol(length_tukey_results), 1:(ncol(length_tukey_results) - 1))]

# View the result
View(length_tukey_results)


###############################################################################
################################################################################

library(rcompanion)

#######################
## jared_mamrot code ##

cldList2 <- function (formula = NULL, data = NULL, comparison = NULL, p.value = NULL, 
                      threshold = 0.05, print.comp = FALSE, desired_order = desired_order, ...) 
{
  if (!is.null(formula)) {
    p.value = eval(parse(text = paste0("data", "$", all.vars(formula[[2]])[1])))
    comparison = eval(parse(text = paste0("data", "$", all.vars(formula[[3]])[1])))
  }
  FLAG = 0
  Comparison = data[data[[p.value]] <= threshold,]
  Comparison2 <- Comparison
  Comparison2$Comparison <- paste(gsub(".*-", "", Comparison$Comparison),
                            gsub("-.*", "", Comparison$Comparison),
                            sep = "-")
  Comparison <- rbind(Comparison, Comparison2)
  order_df = Comparison[order(-rowSums(sapply(seq_along(desired_order), function(i) {
    i * grepl(desired_order[i], Comparison[[comparison]])})),
    Comparison[[comparison]], decreasing = TRUE),]
  Comparison = order_df[[p.value]]
  names(Comparison) <- order_df[[comparison]]
  if (sum(data[data[[p.value]] <= threshold,][[p.value]], na.rm = TRUE) == 0) {
    FLAG = 1
  }
  
  if (print.comp == TRUE) {
    Y = data.frame(Comparisons = Comparison, p.value = p.value, 
                   Value = Comparison, Threshold = threshold)
    cat("\n", "\n")
    print(Y)
    cat("\n", "\n")
  }
  
  MCL = multcompView::multcompLetters(Comparison)
  Group = names(MCL$Letters)
  Letter = as.character(MCL$Letters)
  if (FLAG == 0) {
    MonoLetter = as.character(MCL$monospacedLetters)
  }
  if (FLAG == 1) {
    MonoLetter = Letter
  }
  Z = data.frame(Group, Letter, MonoLetter)
  return(Z)
}

###############################################################################
################################################################################

desired_order <- c(
  "Summer:Beggers:Mid", "Summer:Beggers:Low",
  "Winter:Beggers:Mid", "Winter:Beggers:Low",
  "Summer:Looe:Mid", "Summer:Looe:Low", 
  "Winter:Looe:Mid", "Winter:Looe:Low",
  "Summer:Noss:Mid", "Summer:Noss:Low",
  "Winter:Noss:Mid", "Winter:Noss:Low"
)

# Use cldList2 to get compact letter display
length_cld2 <- cldList2(
  data =  length_tukey_results,
  p.value = "p adj",
  comparison = "Comparison",
  threshold = 0.05,
  desired_order = desired_order
)

# View results
print(length_cld2)

# Group Letter MonoLetter
#1  Summer:Beggers:Mid     ab    ab     
#2  Summer:Beggers:Low      c      c    
#3  Winter:Beggers:Mid      d       d   
#4  Winter:Beggers:Low      d       d   
#5     Summer:Looe:Mid     ef        ef 
#6     Summer:Looe:Low      e        e  
#7     Winter:Looe:Mid     ef        ef 
#8     Winter:Looe:Low     fg         fg
#9     Summer:Noss:Mid    afg    a    fg
#10    Summer:Noss:Low     ef        ef 
#11    Winter:Noss:Mid     ag    a     g
#12    Winter:Noss:Low     bc     bc 

Solution

  • I've adapted the cldList function to allow you to input desired_order, and I think the output is correct, but I'm not certain:

    library(rcompanion)
    
    cldList2 <- function (formula = NULL, data = NULL, comparison = NULL, p.value = NULL, 
              threshold = 0.05, print.comp = FALSE, desired_order = desired_order, ...) 
    {
      if (!is.null(formula)) {
        p.value = eval(parse(text = paste0("data", "$", all.vars(formula[[2]])[1])))
        comparison = eval(parse(text = paste0("data", "$", all.vars(formula[[3]])[1])))
      }
      FLAG = 0
      Comparison = data[data[[p.value]] <= threshold,]
      Comparison2 <- Comparison
      Comparison2$diff <- paste(gsub(".*-", "", Comparison$diff),
                                gsub("-.*", "", Comparison$diff),
                                sep = "-")
      Comparison <- rbind(Comparison, Comparison2)
      order_df = Comparison[order(-rowSums(sapply(seq_along(desired_order), function(i) {
        i * grepl(desired_order[i], Comparison[[comparison]])})),
        Comparison[[comparison]], decreasing = TRUE),]
      Comparison = order_df[[p.value]]
      names(Comparison) <- order_df[[comparison]]
      if (sum(data[data[[p.value]] <= threshold,][[p.value]], na.rm = TRUE) == 0) {
        FLAG = 1
      }
      
      if (print.comp == TRUE) {
        Y = data.frame(Comparisons = Comparison, p.value = p.value, 
                       Value = Comparison, Threshold = threshold)
        cat("\n", "\n")
        print(Y)
        cat("\n", "\n")
      }
      
      MCL = multcompView::multcompLetters(Comparison)
      Group = names(MCL$Letters)
      Letter = as.character(MCL$Letters)
      if (FLAG == 0) {
        MonoLetter = as.character(MCL$monospacedLetters)
      }
      if (FLAG == 1) {
        MonoLetter = Letter
      }
      Z = data.frame(Group, Letter, MonoLetter)
      return(Z)
    }
    
    
    length_tukey2 <- read.table(text = "
    diff         lwr          upr     p adj
    'Winter:Beggers:Mid-Summer:Beggers:Mid'  29.4223913  19.8928280  38.95195464 0.0000000
    'Summer:Looe:Mid-Summer:Beggers:Mid'    -17.0816085 -26.3374620  -7.82575506 0.0000001
    'Winter:Looe:Mid-Summer:Beggers:Mid'    -15.2041608 -24.1435742  -6.26474731 0.0000018
    'Summer:Noss:Mid-Summer:Beggers:Mid'     -9.1104143 -18.3054013   0.08457279 0.0548154
    'Winter:Noss:Mid-Summer:Beggers:Mid'     -2.2282797 -11.4180417   6.96148231 0.9997435
    'Summer:Beggers:Low-Summer:Beggers:Mid'  13.0708662   3.4300630  22.71166931 0.0005807
    'Winter:Beggers:Low-Summer:Beggers:Mid'  23.8704968  14.2899835  33.45101004 0.0000000
    'Summer:Looe:Low-Summer:Beggers:Mid'    -20.2690529 -29.5565237 -10.98158210 0.0000000
    'Winter:Looe:Low-Summer:Beggers:Mid'     -9.7459188 -18.5546802  -0.93715738 0.0157650
    'Summer:Noss:Low-Summer:Beggers:Mid'    -11.9838481 -21.0283902  -2.93930611 0.0009105
    'Winter:Noss:Low-Summer:Beggers:Mid'      7.9324954  -1.1718230  17.03681388 0.1602939
    'Summer:Looe:Mid-Winter:Beggers:Mid'    -46.5039998 -55.7168884 -37.29111130 0.0000000
    'Winter:Looe:Mid-Winter:Beggers:Mid'    -44.6265521 -53.5214723 -35.73163191 0.0000000
    'Summer:Noss:Mid-Winter:Beggers:Mid'    -38.5328056 -47.6845420 -29.38106919 0.0000000
    'Winter:Noss:Mid-Winter:Beggers:Mid'    -31.6506710 -40.7971576 -22.50418438 0.0000000
    'Summer:Beggers:Low-Winter:Beggers:Mid' -16.3515252 -25.9510865  -6.75196384 0.0000017
    'Winter:Beggers:Low-Winter:Beggers:Mid'  -5.5518946 -15.0909053   3.98711623 0.7580746
    'Summer:Looe:Low-Winter:Beggers:Mid'    -49.6914442 -58.9360971 -40.44679139 0.0000000
    'Winter:Looe:Low-Winter:Beggers:Mid'    -39.1683101 -47.9319149 -30.40470528 0.0000000
    'Summer:Noss:Low-Winter:Beggers:Mid'    -41.4062395 -50.4068079 -32.40567100 0.0000000
    'Winter:Noss:Low-Winter:Beggers:Mid'    -21.4898959 -30.5505309 -12.42926090 0.0000000
    'Winter:Looe:Mid-Summer:Looe:Mid'         1.8774477  -6.7235900  10.47848551 0.9999087
    'Summer:Noss:Mid-Summer:Looe:Mid'         7.9711942  -0.8951762  16.83756468 0.1275696
    'Winter:Noss:Mid-Summer:Looe:Mid'        14.8533288   5.9923772  23.71428043 0.0000028
    'Summer:Beggers:Low-Summer:Looe:Mid'     30.1524747  20.8245691  39.48038029 0.0000000
    'Winter:Beggers:Low-Summer:Looe:Mid'     40.9521053  31.6865253  50.21768526 0.0000000
    'Summer:Looe:Low-Summer:Looe:Mid'        -3.1874444 -12.1496903   5.77480151 0.9916068
    'Winter:Looe:Low-Summer:Looe:Mid'         7.3356897  -1.1294751  15.80085454 0.1664206
    'Summer:Noss:Low-Summer:Looe:Mid'         5.0977604  -3.6124910  13.80801170 0.7513767
    'Winter:Noss:Low-Summer:Looe:Mid'        25.0141039  16.2417979  33.78640992 0.0000000
    'Summer:Noss:Mid-Winter:Looe:Mid'         6.0937465  -2.4417567  14.62924969 0.4524766
    'Winter:Noss:Mid-Winter:Looe:Mid'        12.9758811   4.4460069  21.50575525 0.0000430
    'Summer:Beggers:Low-Winter:Looe:Mid'     28.2750269  19.2610315  37.28902233 0.0000000
    'Winter:Beggers:Low-Winter:Looe:Mid'     39.0746575  30.1251736  48.02414145 0.0000000
    'Summer:Looe:Low-Winter:Looe:Mid'        -5.0648921 -13.6999452   3.57016094 0.7486876
    'Winter:Looe:Low-Winter:Looe:Mid'         5.4582420  -2.6597199  13.57620387 0.5513244
    'Summer:Noss:Low-Winter:Looe:Mid'         3.2203126  -5.1529047  11.59352994 0.9841118
    'Winter:Noss:Low-Winter:Looe:Mid'        23.1366562  14.6989051  31.57440721 0.0000000
    'Winter:Noss:Mid-Summer:Noss:Mid'         6.8821346  -1.9152189  15.67948801 0.3046563
    'Summer:Beggers:Low-Summer:Noss:Mid'     22.1812804  12.9137680  31.44879289 0.0000000
    'Winter:Beggers:Low-Summer:Noss:Mid'     32.9809110  23.7761331  42.18568895 0.0000000
    'Summer:Looe:Low-Summer:Noss:Mid'       -11.1586386 -20.0580103  -2.25926699 0.0024611
    'Winter:Looe:Low-Summer:Noss:Mid'        -0.6355045  -9.0340746   7.76306555 1.0000000
    'Summer:Noss:Low-Summer:Noss:Mid'        -2.8734339 -11.5189785   5.77211077 0.9952838
    'Winter:Noss:Low-Summer:Noss:Mid'        17.0429097   8.3348492  25.75097011 0.0000000
    'Summer:Beggers:Low-Winter:Noss:Mid'     15.2991459   6.0368175  24.56147417 0.0000044
    'Winter:Beggers:Low-Winter:Noss:Mid'     26.0987764  16.8992180  35.29833487 0.0000000
    'Summer:Looe:Low-Winter:Noss:Mid'       -18.0407732 -26.9347461  -9.14680029 0.0000000
    'Winter:Looe:Low-Winter:Noss:Mid'        -7.5176391 -15.9104883   0.87521012 0.1311895
    'Summer:Noss:Low-Winter:Noss:Mid'        -9.7555684 -18.3955558  -1.11558113 0.0120661
    'Winter:Noss:Low-Winter:Noss:Mid'        10.1607751   1.4582321  18.86331813 0.0075546
    'Winter:Beggers:Low-Summer:Beggers:Low'  10.7996306   1.1494889  20.44977230 0.0135847
    'Summer:Looe:Low-Summer:Beggers:Low'    -33.3399191 -42.6991986 -23.98063950 0.0000000
    'Winter:Looe:Low-Summer:Beggers:Low'    -22.8167849 -31.7012251 -13.93234475 0.0000000
    'Summer:Noss:Low-Summer:Beggers:Low'    -25.0547143 -34.1729784 -15.93645018 0.0000000
    'Winter:Noss:Low-Summer:Beggers:Low'     -5.1383707 -14.3159312   4.03918965 0.8016093
    'Summer:Looe:Low-Winter:Beggers:Low'    -44.1395497 -53.4367139 -34.84238539 0.0000000
    'Winter:Looe:Low-Winter:Beggers:Low'    -33.6164155 -42.4353966 -24.79743448 0.0000000
    'Summer:Noss:Low-Winter:Beggers:Low'    -35.8543449 -44.9088405 -26.79984933 0.0000000
    'Winter:Noss:Low-Winter:Beggers:Low'    -15.9380013 -25.0522081  -6.82379462 0.0000007
    'Winter:Looe:Low-Summer:Looe:Low'        10.5231341   2.0234102  19.02285801 0.0030441
    'Summer:Noss:Low-Summer:Looe:Low'         8.2852048  -0.4586370  17.02904655 0.0830012
    'Winter:Noss:Low-Summer:Looe:Low'        28.2015483  19.3958886  37.00720806 0.0000000
    'Summer:Noss:Low-Winter:Looe:Low'        -2.2379294 -10.4715150   5.99565630 0.9992360
    'Winter:Noss:Low-Winter:Looe:Low'        17.6784142   9.3792090  25.97761940 0.0000000
    'Winter:Noss:Low-Summer:Noss:Low'        19.9163435  11.3672927  28.46539437 0.0000000",
                                header = TRUE)
    
    desired_order <- c(
      "Summer:Beggers:Mid", "Summer:Beggers:Low",
      "Winter:Beggers:Mid", "Winter:Beggers:Low",
      "Summer:Looe:Mid", "Summer:Looe:Low", 
      "Winter:Looe:Mid", "Winter:Looe:Low",
      "Summer:Noss:Mid", "Summer:Noss:Low",
      "Winter:Noss:Mid", "Winter:Noss:Low"
    )
    
    # Use cldList2 to get compact letter display
    length_cld2 <- cldList2(
      data =  length_tukey2,
      p.value = "adj",
      comparison = "diff",
      threshold = 0.05,
      desired_order = desired_order
    )
    
    # View results
    print(length_cld2)
    #>                 Group Letter MonoLetter
    #> 1  Summer:Beggers:Mid     ab    ab     
    #> 2  Summer:Beggers:Low      c      c    
    #> 3  Winter:Beggers:Mid      d       d   
    #> 4  Winter:Beggers:Low      d       d   
    #> 5     Summer:Looe:Mid     ef        ef 
    #> 6     Summer:Looe:Low      e        e  
    #> 7     Winter:Looe:Mid     ef        ef 
    #> 8     Winter:Looe:Low     fg         fg
    #> 9     Summer:Noss:Mid    afg    a    fg
    #> 10    Summer:Noss:Low     ef        ef 
    #> 11    Winter:Noss:Mid     ag    a     g
    #> 12    Winter:Noss:Low     bc     bc
    

    Created on 2025-05-14 with reprex v2.1.1

    Is this the expected outcome with this data? What are the letters expected to be for the comparisons?