0

I am trying to fill shapes with colors gradient corresponding to a continuous variable. I don't have any errors, but it does not print on the graph.

I tried to use as.numeric to make sure the variable is continuous.

The NMDS is already calculated and it works. Everything works except the color gradient.

ggplot()+ 
        geom_point(data = NMDS.all.taxa, aes(y = NMDS2, x = NMDS1, fill = env$elev.num), shape = env$saison, size = 4)+ #this is the points
        geom_path(data = df_ell.all.taxa, aes(x = NMDS1, y = NMDS2, colour = group))+     ##Elipses
        scale_fill_gradient2(low = "green", mid = "blue", high = "red", midpoint = 1800)+   ##fill
        theme_bw()+
        theme(panel.background = element_blank(), 
              panel.grid.major = element_blank(),  #remove major-grid labels
              panel.grid.minor = element_blank(),  #remove minor-grid labels
              plot.background = element_blank() 
        ) 

It gives me a NMDS with everything except that the shapes are empty. Not any Error codes.

To recreate aspects of the data:

library(vegan)
Macro_AUG_2019_rep.<- matrix(0:10, ncol = 20, nrow = 50) 
env <- data.frame(Traitement = sample(c("n","r"),50, replace = TRUE), 
                  saison = sample(c("S","A"),50, replace = TRUE),
                  Elevation = sample(1000:1049), 
                  Site = sample(c("lake1","lake2","lake3","lake4","lake5","lake6","lake7"), 
                                50, replace = TRUE))

spe.nmds <- metaMDS(Macro_AUG_2019_rep., distance='bray', k=2, try=999, maxit=500)
NMDS.all.taxa <- data.frame(NMDS1 = spe.nmds$points[,1],
                            NMDS2 = spe.nmds$points[,2], 
                            group = env$Traitement,
                            sites = env$Site)

veganCovEllipse <- function(cov, center = c(0, 0), scale = 1.75, npoints = 100) { 
  theta <- (0:npoints) * 2 * pi/npoints 
  Circle <- cbind(cos(theta), sin(theta)) 
  t(center + scale * t(Circle %*% chol(cov))) 
}

df_ell.all.taxa <- data.frame()
for(g in levels(NMDS.all.taxa$group)){ 
  df_ell.all.taxa <- rbind(
    df_ell.all.taxa, 
    cbind(as.data.frame(with(NMDS.all.taxa[NMDS.all.taxa$group == g, ], 
                             veganCovEllipse(cov.wt(cbind(NMDS1, NMDS2),
                                                    wt=rep(1 / length(NMDS1), 
                                                           length(NMDS1)))$cov,
                                             center=c(mean(NMDS1), mean(NMDS2))))),
          group = g)
  ) 
}
NMDS.mean.all.taxa = aggregate(NMDS.all.taxa[ ,c("NMDS1", "NMDS2")], 
                               list(group = NMDS.all.taxa$group), 
                               mean)
Community
  • 1
  • 1
  • Care to provide a [reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example)? – Roman Luštrik Aug 31 '19 at 19:19
  • It is really difficult to figure out what is wrong when we don't have a reproducible example or illustration of the problem. If you don't want to share your data, that is fine, but could you then demonstrate the problem with a build-in dataset (iris for example). What type of variable is `env$saison`? – teunbrand Aug 31 '19 at 19:25
  • Here is a code to create data of the same type: – Julien Beaulieu Aug 31 '19 at 20:28
  • Macro_AUG_2019_rep.<- matrix(0:10, ncol = 20, nrow = 50) env <- data.frame( Traitement = sample(c("n","r"),50, replace = TRUE), saison = sample(c("S","A"),50, replace = TRUE), Elevation = sample(1000:1049), Site = sample(c("lake1","lake2","lake3","lake4","lake5","lake6","lake7"), 50, replace = TRUE) ) – Julien Beaulieu Aug 31 '19 at 20:29
  • Using vegan package, I than apply that code to the previous one : – Julien Beaulieu Aug 31 '19 at 20:31
  • spe.nmds <- metaMDS(Macro_AUG_2019_rep., distance='bray', k=2, try=999, maxit=500) NMDS.all.taxa <- data.frame(NMDS1 = spe.nmds$points[,1], ##fait tableau avec coordonnees NMDS NMDS2 = spe.nmds$points[,2], group = env$Traitement, ## groupes pour élipses sites = env$Site) ###Plot NMDS avec élipses veganCovEllipse<-function (cov, center = c(0, 0), scale = 1.75, npoints = 100) { theta <- (0:npoints) * 2 * pi/npoints Circle <- cbind(cos(theta), sin(theta)) t(center + scale * t(Circle %*% chol(cov))) } – Julien Beaulieu Aug 31 '19 at 20:32
  • ### df_ell.all.taxa <- data.frame() for(g in levels(NMDS.all.taxa$group)){ df_ell.all.taxa <- rbind(df_ell.all.taxa, cbind(as.data.frame(with(NMDS.all.taxa[NMDS.all.taxa$group==g,], veganCovEllipse(cov.wt(cbind(NMDS1,NMDS2),wt=rep(1/length(NMDS1), length(NMDS1)))$cov,center=c(mean(NMDS1),mean(NMDS2))))),group=g)) } – Julien Beaulieu Aug 31 '19 at 20:32
  • # data for labelling the ellipse NMDS.mean.all.taxa=aggregate(NMDS.all.taxa[ ,c("NMDS1", "NMDS2")], list(group = NMDS.all.taxa$group), mean) – Julien Beaulieu Aug 31 '19 at 20:32
  • And then I do the ggplot one. env$saison is factor. Thank you! – Julien Beaulieu Aug 31 '19 at 20:34
  • I took the liberty of formatting the code and appending it to your question for easier copy-pasting. – teunbrand Aug 31 '19 at 21:25

1 Answers1

1

ggplot2 doesn't play nice with $ operators in aes() functions, so it would be good practise to avoid these by appending the env$Elevation and env$saison to your main data.frame:

df <- cbind(NMDS.all.taxa, Elevation = env$Elevation, Saison = env$saison)

Now, if I understood correctly, the problem was that the geom_point shapes aren't filled. The shape aesthetic in ggplot2 is (I think) identical to the pch argument in base R plots, so we can see what the values would mean:

enter image description here

Factor variables are integers dressed up with a level-label, so the env$saison that you were using would pass down 1s and 2s as shapes. These shapes are line-only, without any fill associated with them.

Thus, to fix the problem we need to let ggplot know what shapes we actually want, 21 and 24 for example. To map your factor variable to these shapes, we'll define the shapes inside the aes() function. Then, we can use scale_shape_manual() to set the correct shapes.

# I defined the xy mapping in the main `ggplot()` call so that we
# don't need to do this seperately for the path and points
ggplot(data = df, aes(NMDS1, NMDS2))+ 
  geom_point(aes(fill = Elevation, shape = Saison), 
             size = 4) +
  geom_path(data = df_ell.all.taxa, 
            aes(colour = group)) +
  scale_shape_manual(values = c(21, 24)) +
  scale_fill_gradient2(low = "green", mid = "blue", high = "red",
                       # I adjusted the midpoint to match example
                       midpoint = mean(df$Elevation))

Which gave me the following plot:

enter image description here

As an aside, your problem would have been easily illustrated with a build-in dataset. It is more in line with what a minimal reproducible example is, and it would have saved your time copying your data analysis code. Example below:

ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
  geom_point(aes(fill = Petal.Width), shape = iris$Species) +
  scale_fill_gradient()

To which the answer would have been:

ggplot(iris, aes(Sepal.Width, Sepal.Length)) +
  geom_point(aes(fill = Petal.Width, shape = Species)) +
  scale_fill_gradient() +
  scale_shape_manual(values = c(21, 22, 24))
teunbrand
  • 33,645
  • 4
  • 37
  • 63