如何在ade4的s.class图中按两类变量分设椭圆与符号颜色
Hey there! I totally get your frustration—ade4's s.class() function does tie the grouping factor to both the ellipses and point styling by default, which makes separating those two variables tricky. But don't worry, we can work around this by splitting the plotting into two separate steps: first drawing the morphometric cluster ellipses, then overlaying the points colored by genetic cluster (plus handling those NA ggpop samples).
Step 1: Prep your data
First, let's clean up the grouping variables and handle those NA ggpop entries by creating a dedicated color group (so we can style those samples differently):
# Load ade4 if you haven't already library(ade4) # Convert grouping columns to factors (critical for consistent coloring) df$Morph.cluster <- as.factor(df$Morph.cluster) df$ALL <- as.factor(df$ALL) # Create a color group: use ALL, but mark NA ggpop samples as a separate category df$color_group <- df$ALL df$color_group[is.na(df$ggpop)] <- "Missing"
Step 2: Set up the dudi object (required for ade4 plotting)
ade4 relies on ordination objects for most plots, so let's create one from your RW1 and RW2 data:
# Create a PCA dudi from RW1 and RW2 (we just need the scores for plotting) dudi_rw <- dudi.pca(df[, c("RW1", "RW2")], scannf = FALSE, nf = 2)
Step 3: Draw the morphometric cluster ellipses (no points yet)
We'll use s.class() to draw the ellipses based on Morph.cluster, but tell it not to plot any points:
# Plot ellipses for Morph.cluster, hide points s.class(dudi_rw$li, fac = df$Morph.cluster, col = 1:nlevels(df$Morph.cluster), # Color for ellipse borders lwd = 2, # Make ellipses easier to see show.points = FALSE, # Don't draw the default points ellipse = TRUE) # Ensure ellipses are drawn
Step 4: Overlay points colored by genetic cluster (with NA handling)
Now use base R's points() to add your data points, styling them based on color_group and marking NA ggpop samples with a distinct symbol:
# Define a custom color palette for your genetic clusters + missing samples # Replace the values with your actual cluster names/colors! color_palette <- c( "Cluster1" = "#E69F00", "Cluster2" = "#56B4E9", "Cluster3" = "#009E73", "Missing" = "#999999" ) # Add the points: solid circles for non-NA, hollow for NA ggpop points(dudi_rw$li$RW1, dudi_rw$li$RW2, col = color_palette[df$color_group], pch = ifelse(is.na(df$ggpop), 1, 19), # 1 = hollow circle, 19 = solid cex = 1.2) # Adjust point size if needed
Step 5: Add clear legends
Since we have two separate grouping systems, add two legends to make the plot easy to interpret:
# Legend for Morph.cluster ellipses legend("topright", legend = levels(df$Morph.cluster), col = 1:nlevels(df$Morph.cluster), lty = 1, lwd = 2, title = "Morphometric Cluster") # Legend for genetic cluster points legend("bottomright", legend = names(color_palette), col = color_palette, pch = c(19, 19, 19, 1), # Match pch values from points() title = "Genetic Cluster (ALL)")
Why this works
The key here is breaking the plot into two parts: s.class() handles the ellipse grouping (tied to Morph.cluster), while base R's points() gives us full control over point coloring/symbols tied to ALL (and our custom missing category). This bypasses the default link between fac and point styling in s.class().
内容的提问来源于stack exchange,提问作者Ella Bowles

