You can use the ncol = parameter instead of horiz to get the ncol = layout. Note that horiz overrides ncol , so you should not use both together. Although this does not indicate the number of rows directly, it does so indirectly because the number of rows is determined by the number of columns and factors.
MyCol <- topo.colors(20) barplot(rep(1,20), yaxt="n", col=MyCol) x <- 1:20 MyLab <- paste("Zone",x) legend("bottom",MyLab,fill=MyCol,ncol=5)

If you want to arrange legend items arranged in rows, you can do this by indexing them in the order you need. for instance
MyOrder = matrix(1:20, nrow = 4, ncol = 5, byrow = T) legend("bottom",MyLab[MyOrder], fill=MyCol[MyOrder] ,ncol=5)

To summarize for a different number of lines and factors, we can do something like
Nfact = 21 Nrows = 5 Ncols = ceiling(Nfact / Nrows) MyOrder = matrix(1:(Nrows*Ncols), nrow=Nrows, ncol=Ncols, byrow=T) MyCol <- topo.colors(Nfact) x <- 1:Nfact MyLab <- paste("Zone",x) barplot(rep(1,Nfact), yaxt="n", col=MyCol) legend("bottom", MyLab[MyOrder], fill = MyCol[MyOrder], ncol = Ncols, border=NA)

And the last additional trick: in the previous chart, we set border = NA. This is necessary to prevent the drawing of borders around empty legend elements (those located at the bottom of incomplete columns). If you need borders, then we also need to create a vector of border colors, which will be NA only in those places that we do not want to draw.
MyBorders = rep("black", Nrows*Ncols) MyBorders[MyOrder > Nfact] <- NA legend("bottom", MyLab[MyOrder], fill = MyCol[MyOrder], ncol = Ncols, border=MyBorders)
