I have a pretty involved solution that requires you specify some hyperparameters of your model. Not being an expert in the relation between snake length and age, so I picked some values that seemed vaguely possible. But, by all means feel to tweak them. This series of functions is adapted and expanded from [Gelman and Hill (2007)][1]. First, we need a function to simulate data sets with the properties you want. Here is where I "invented" some numbers (under the comment `#Specifying hyperparameters`. Feel free to adjust accordingly based on your knowledge base and expectations. #Creating fake dataframe for simulations fake<-function(J, K){ snake<-(1:(J*K)) #creates a snake or case id habitat<-rep(1:J, K) #creates a balanced grouping variable age<-rnorm(J*K, 2.5, .75) #creates a random normal age variable #Specifying hyperparameters mu.a.true<-12 #grand intercept mu.g1.true<-3 #grand age slope sigma.y.true<-1.65 #residual sd sigma.a.true<-2.30 #intercept sd sigma.g1.true<-2.15 #age slope sd #habitat-level parameters a.true<-rnorm(J, mu.a.true, sigma.a.true) #vector of random intercepts g1.true<-rnorm(J, mu.g1.true, sigma.g1.true) #vector of random slopes #dependent variable y<-rnorm(J*K, a.true[habitat]+g1.true[habitat]*age, sigma.y.true) return(data.frame(snake, y, habitat, age)) } and if you run `print(fake(5,5))` you get the following simulated data (where y = length): > print(fake(5,5)) snake y habitat age 1 1 21.85790 1 1.9030948 2 2 27.73040 2 2.4382916 3 3 11.60743 3 0.7640231 4 4 15.63832 4 2.9965471 5 5 26.83866 5 1.8319489 6 6 24.65482 1 3.0666732 7 7 27.42804 2 2.2352739 8 8 16.98225 3 3.5354592 9 9 15.32236 4 3.0284722 10 10 25.22085 5 2.4662031 11 11 18.39988 1 2.2474545 12 12 21.85225 2 1.2652154 13 13 14.12972 3 2.6137810 14 14 17.69987 4 1.3900062 15 15 33.13150 5 3.2806024 16 16 28.80915 1 4.6216763 17 17 35.61110 2 2.5738612 18 18 15.78296 3 2.5815051 19 19 17.76041 4 3.2101400 20 20 29.23588 5 2.5638092 21 21 21.51020 1 2.7942239 22 22 32.10491 2 2.6981291 23 23 10.05619 3 1.7800981 24 24 16.96727 4 3.0558285 25 25 34.61646 5 3.3928710 Up next? We need to simulate a bunch of data and see how many data sets "recover" a significant effect for age given the hyperparameters we input in our data simulation function. Again, those hyperparameters can be adjusted to better fit your expectations. mixed.power<-function(J, K, n.sims=1000){ signif<-rep(NA, n.sims) #note that you can specify number of simulations - default is 1000 pb<-winProgressBar(title="Progress", min=0, max=100, width=300) #if you want to watch the progress require(lme4) require(arm) for(s in 1:n.sims){ fake.data<-fake(J, K) #calls in data simulation function lme.power<-lmer(y~1+age+(1+age|habitat), data=fake.data) #estimates mixed effect model using each simulated dataset theta.hat<-fixef(lme.power)["age"] #saves age coefficients from each simulated dataset theta.se<-se.fixef(lme.power)["age"] #saves standard error of age coefficients from each simulated dataset signif[s]<-ifelse((abs(theta.hat)-qt(.975, J*K-1)*theta.se)>0, 1, 0)#assigns value of 1 to significant coefficients 0 to ns coefficients setWinProgressBar(pb, s/n.sims*100, title=paste(round(s/n.sims*100, 0), "% done")) } close(pb) power<-mean(signif, na.rm=T)#calculates proportion of significant models out of # of simulated datasets... return(power) } You may get some warnings with these codes when models don't converge in your simulations. I find that happens more often when dealing with small samples like the ones you are proposing. (I tend to ignore these convergence warnings) You can pause here and calculate power for a given number of habitats (J) with a given number of snakes per habitat (K). In that case you can run `mixed.power(5,10)` and see the following returned: > mixed.power(5, 10) [1] 0.804 Or perhaps more instructively you can go all out and create a power plot to get a sense of how many snakes per habitat you should consider gathering. Here is the function for that: graph.power<-function(J, max.K){ require(ggplot2) KK<-seq(3, max.K, by=1) #will ieterate from 3 cases to the max.K specified in the function above Y<-rep(NA, length(KK)) #Empty vector to contain power estimates from mixed.power () function JJ<-rep(J, length(KK)) #Repeates the number of habitats you specified to equal the length of the KK vector pb2<-winProgressBar(title="Overall Progress", min=0, max=100, width=300) #for an overall progress bar for(i in 1:length(KK)){ Y[i]<-mixed.power(JJ[i], KK[i]) #runs mixed power function and stores results one at a time setWinProgressBar(pb2, i/length(KK)*100, title=paste(round(i/length(KK)*100, 0), "% Overall complete")) } close(pb2) DF<-as.data.frame(cbind(KK, Y)) #creates data frame for plotting colnames(DF)<-c("KK", "Y") #Code below provides a basic power plot with a horizontal line at .80 g1<-ggplot(aes(x=KK, y=Y), data=DF) g2<-g1+geom_smooth(se=F)+geom_hline(yintercept = .8, lty="dashed", col="red", lwd=2) g3<-g2+xlab("Sample Size per Habitat")+ylab("Power") g4<-g3+ggtitle("Power Analysis") return(g4) } When you use this function, the only difference is that now the second number is the maximum number of snakes you want to consider examining in a power analysis. So in this example, let's say I wanted to look at a power curve that considered up to 15 snakes per habitat (holding the number of habitats constant at 5). Here is what that would look like: `graph.power(5,15)`... which would return the following image: [![enter image description here][2]][2] Now you have the ability to assess the sample size at which the power curve crosses .80 (~9 snakes per 5 habitats in this case). This is NOT the only way to approach a power analysis in a mixed model, but I tend to like it as it gives me a great deal of control over the various hyperparameters and allows me to plot various power curves to get a sense of how changing those hyperparameters in addition to sample and cluster size change the power of my model. A note: if you want to play around to get a sense of how the functions work or to try to identify some good starting values you may want to lower the number of simulations in the `mixed.power()` function to reduce computation time prior to running your "official" power analyses with the larger set of simulated data sets. [1]: https://g.co/kgs/M5ELVg [2]: https://i.sstatic.net/gLzlZ.jpg