Lab 3 — Vegetation Tables and Summaries

Before moving on to formal statistical models it's helpful to review some of the more traditional approaches to vegetation analysis using sorted vegetation tables. Building on the extensive capabilities of R to work with matrices and data.frames, The vegan and LabDSV libraries enable vegetation ecologists to use R for such work (see R for Ecologists if you are unfamiliar with libraries).

In Lab 1 and Lab 2 we explored a dataset from Bryce Canyon National Park. While the Bryce Canyon vegetation data is relatively modest in size (160 plots x 169 species), it's too large to see easily just by listing the whole matrix. For example, if you have loaded the vegetation data file in previous labs, then

veg
will list the entire matrix to your screen, but it's likely to wrap and scroll off. You can control the wrapping aspects with the options() as follows. Suppose you have your window set to a width of 200 characters,
options(width=200)
will produce output that does not wrap unless it's more than 200 characters wide. In addition, to control the periodic insertion of the column headings,
options(height=100)
will cause the column headings to be inserted only every 100 lines. These can of course be combined in a single call.
options(height=100,width=200)
Still, the Bryce vegetation data will scroll uncontrollably. As a first step toward solving this (and other) problem, load the LabDSV and vegan libraries.
library(labdsv)
library(vegan)

This provides several functions we will need. The first is vegtab(), which produces sorted vegetation tables with several specifiers. Specifically,
1. the vegetation matrix to list
2. set= a specific subset of plots within that matrix to list (optional)
3. min= a minimum number of plots a species must occur in to be included (optional)
4. pltord= a specific order for the plots (optional)
5. spcord= a specific order for the species (optional)
6. pltlbl= an alternative plot label for the plots (optional)

The default behavior is to list plots in the order in which they occur in the matrix, but to list species in order from most common to least common. You can specify alternative orders with the optional function arguments. For example, to see the list of most common species that occur on sites with deep soils,

vegtab(veg,site$depth=="deep",min=20)  chrvis artarb sticom senmul sithys poafen calnut erirac koenit 1 0.0 0.0 0.0 0.0 0.0 0.5 0.0 0.0 0.0 8 0.0 0.0 0.0 0.5 0.0 0.0 0.0 0.0 0.0 12 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 13 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 20 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 1.0 2.0 0.5 0.0 0.5 2.0 0.5 0.5 1.0 119 0.5 2.0 0.5 0.5 0.5 0.0 0.5 0.0 0.5 121 0.5 2.0 2.0 0.5 0.5 0.0 0.0 0.5 0.5 122 1.0 2.0 2.0 0.5 0.5 0.0 0.0 0.5 0.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150 0.0 0.0 0.0 0.0 0.0 0.5 0.0 0.5 0.5 154 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 158 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 160 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0  where ellipses represent omitted material (to save space). As you can see, there are only 9 species which occur at least 20 times in the set of plots on deep soils (n=56), and the most common is chrvis, followed by artarb, etc. The plots can be ordered by another variable. For example, to list plots in order of their elevation, vegtab(veg,site$depth=="deep",min=20,pltord=elev)
    chrvis artarb sticom senmul sithys poafen calnut erirac koenit
89     0.0    0.0    0.0    0.0    2.0    0.0    0.0    0.0    0.0
90     0.5    0.0    0.0    0.0    5.0    0.0    0.5    0.0    0.0
99     0.5    0.0    0.0    0.0    1.0    0.5    0.5    0.0    0.0
88     0.5    0.0    0.0    0.0    1.0    0.0    0.5    0.0    0.0
98     0.5    0.0    0.0    0.0    1.0    0.0    0.5    0.0    0.0
93     0.5    0.0    0.5    0.0    1.0    0.0    0.5    0.0    0.0
.      .      .      .      .      .      .      .      .      .
.      .      .      .      .      .      .      .      .      .
.      .      .      .      .      .      .      .      .      .
105    2.0    2.0    0.5    0.5    0.5    0.5    0.5    0.5    0.0
102    1.0    2.0    1.0    0.0    0.5    2.0    0.5    0.0    0.0
103    0.5    2.0    2.0    0.5    0.5    0.5    0.5    0.5    0.0
40     0.0    0.0    0.0    0.5    0.0    0.0    0.0    0.5    0.0
38     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0
.      .      .      .      .      .      .      .      .      .
.      .      .      .      .      .      .      .      .      .
.      .      .      .      .      .      .      .      .      .
33     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0
31     0.0    0.0    0.0    0.5    0.0    0.0    0.0    0.0    0.0
30     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0
65     0.0    0.0    0.0    0.5    0.5    0.5    0.0    0.0    0.0
8      0.0    0.0    0.0    0.5    0.0    0.0    0.0    0.0    0.0
1      0.0    0.0    0.0    0.0    0.0    0.5    0.0    0.0    0.0

To actually list the elevation, specify pltlbl=elev as well as pltord=elev.
vegtab(veg,site$depth=="deep",pltlbl=elev,pltord=elev,min=20)  elev chrvis artarb sticom senmul sithys poafen calnut erirac koenit 89 6650 0.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 0.0 90 6680 0.5 0.0 0.0 0.0 5.0 0.0 0.5 0.0 0.0 99 6720 0.5 0.0 0.0 0.0 1.0 0.5 0.5 0.0 0.0 88 6760 0.5 0.0 0.0 0.0 1.0 0.0 0.5 0.0 0.0 98 6760 0.5 0.0 0.0 0.0 1.0 0.0 0.5 0.0 0.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 7720 0.5 2.0 2.0 0.5 0.5 0.5 0.5 0.5 0.0 40 7800 0.0 0.0 0.0 0.5 0.0 0.0 0.0 0.5 0.0 38 7840 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 135 7850 1.0 0.5 0.0 0.5 0.0 0.0 0.0 0.0 0.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 8560 0.0 0.0 0.0 0.5 0.0 0.0 0.0 0.0 0.0 30 8600 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 65 8660 0.0 0.0 0.0 0.5 0.5 0.5 0.0 0.0 0.0 8 8680 0.0 0.0 0.0 0.5 0.0 0.0 0.0 0.0 0.0 1 8720 0.0 0.0 0.0 0.0 0.0 0.5 0.0 0.0 0.0  Finally, the table can be transposed with the trans=T argument. vegtab(veg,site$depth=="deep",pltlbl=elev,pltord=elev,min=20,trans=T)
         89     90     99     88     98     93  158  160  148    150  154
elev   6650 6680.0 6720.0 6760.0 6760.0 6900.0 6960 7040 7080 7100.0 7300
chrvis    0    0.5    0.5    0.5    0.5    0.5    0    0    0    0.0    0
artarb    0    0.0    0.0    0.0    0.0    0.0    0    0    0    0.0    0
sticom    0    0.0    0.0    0.0    0.0    0.5    0    0    0    0.0    0
senmul    0    0.0    0.0    0.0    0.0    0.0    0    0    0    0.0    0
sithys    2    5.0    1.0    1.0    1.0    1.0    0    0    0    0.0    0
poafen    0    0.0    0.5    0.0    0.0    0.0    0    0    0    0.5    0
calnut    0    0.5    0.5    0.5    0.5    0.5    0    0    0    0.0    0
erirac    0    0.0    0.0    0.0    0.0    0.0    0    0    0    0.5    0
koenit    0    0.0    0.0    0.0    0.0    0.0    0    0    0    0.5    0
.       .     .      .      .      .      .     .    .    .     .     .
.       .     .      .      .      .      .     .    .    .     .     .
.       .     .      .      .      .      .     .    .    .     .     .

It's possible to combine multiple criteria in the set= argument. For example, suppose you wanted to see the vegetation of plots on steep midslopes.
vegtab(veg,site$pos=="mid_slope"&site$slope>20,min=2)
    cermon arcpat ceamar purtri carrss swerad
51     0.5      5    0.5    0.5    0.5    0.5
75     1.0      3    1.0    0.0    0.5    0.5
155    1.0      0    0.0    0.5    0.0    0.0

There are only three plots meeting the criteria, so the number of species occurring at least twice is small, but it illustrates the idea. If the criteria get really complicated, you might want to create a set that is the index to the desired plots. For example
demo <- site$elev>7500 & site$slope<10 & site$av>0.5 vegtab(veg,demo,min=20)   carrss symore senmul berrep arcpat ceamar pacmyr erirac artarb tetcan 1 0.5 1.0 0.0 1.0 1.0 0.5 0.0 0.0 0.0 0.0 2 0.5 0.5 0.5 0.0 0.5 0.0 0.5 0.0 0.0 0.0 3 0.5 0.5 0.5 0.5 1.0 0.5 0.5 0.0 0.0 0.0 4 0.5 0.5 0.5 1.0 1.0 0.5 0.0 0.0 0.0 0.0 6 0.5 0.5 0.0 1.0 1.0 1.0 0.5 0.0 0.0 0.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 0.5 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 138 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 139 0.0 0.0 0.5 0.0 0.0 0.0 0.0 0.0 0.0 2.0 140 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.5 0.5 1.0 141 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0  You can use nested ands and ors as well (remember, & = "and" and | = "or"). demo <- (site$elev>7500 & site$slope<10) | site$pos=="low_slope"
vegtab(veg,demo,pltord=elev,min=35)

    carrss symore senmul arcpat berrep ceamar purtri pacmyr juncom artarb
89     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0
88     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0
157    0.0    0.5    0.0    0.0    0.0    0.0    0.5    0.0    0.0    0.0
76     1.0    0.0    0.0    3.0    0.5    0.0    0.0    0.0    0.0    0.0
84     1.0    0.5    0.0    0.5    0.5    0.0    0.5    0.0    0.0    0.0
77     1.0    0.0    0.0    4.0    0.5    1.0    0.0    0.0    0.0    0.0
.      .      .      .      .      .      .      .      .      .      .
.      .      .      .      .      .      .      .      .      .      .
.      .      .      .      .      .      .      .      .      .      .
85     0.5    1.0    0.0    0.0    3.0    0.0    0.0    0.5    1.0    0.0
46     0.5    0.5    0.5    0.5    0.5    1.0    1.0    0.0    0.0    0.0
58     0.5    0.5    0.5    4.0    0.0    0.0    0.5    0.5    0.5    0.0
61     0.0    0.5    0.0    0.0    1.0    0.0    0.0    0.5    1.0    0.0
87     1.0    1.0    0.5    3.0    1.0    1.0    0.5    0.5    0.5    0.0
60     0.5    1.0    0.5    0.5    1.0    0.0    0.0    0.5    0.2    0.0

So far, we have seen how to subset the data by plots and re-order the table by rows. How do we re-order the species?

Ordering Species in the Table

To order the species, we need a vector of length equal to the number of species. For example, back in Lab 1 we created a vector of the number of plots a species occurs in, called spc.pres. We can order the table by that, which is the reverse of the default ordering.
vegtab(veg,spcord=spc.pres,min=40)
    chrvis oryhym sithys pacmyr ceamar purtri berrep arcpat senmul symore
1      0.0    0.0    0.0    0.0    0.5    0.0    1.0    1.0    0.0    1.0
2      0.0    0.0    0.0    0.5    0.0    0.0    0.0    0.5    0.5    0.5
3      0.0    0.0    0.0    0.5    0.5    0.0    0.5    1.0    0.5    0.5
4      0.0    0.0    0.0    0.0    0.5    0.0    1.0    1.0    0.5    0.5
5      0.0    0.0    0.0    0.5    0.5    0.5    0.5    4.0    0.5    0.5
.       .      .      .      .      .      .      .      .      .      .
.       .      .      .      .      .      .      .      .      .      .
.       .      .      .      .      .      .      .      .      .      .
156    0.0    0.0    0.0    0.0    0.0    0.5    0.0    0.5    0.5    0.5
157    0.0    0.0    0.0    0.0    0.0    0.5    0.0    0.0    0.0    0.5
158    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5    0.0    0.5
159    0.0    0.5    0.0    0.0    0.0    0.5    0.0    0.0    0.0    0.0
160    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5    0.0    0.0


Much more interesting is to order the species by some ecological factor. To do this, we'll use the wascores() function from the vegan library. wascores stands for "weighted average scores", and is used to compute the weighted average value of some environmental variable for all plots in which a species occurs, weighted by the species abundance. For example,

spc.elev <- wascores(elev,veg)
spc.elev

           [,1]
junost 7335.000
ameuta 8138.462
arcpat 8126.099
arttri 6804.082
atrcan 6792.812
berfre 6928.889
ceamar 8200.122
cerled 7776.667
.        .
.        .
.        .
strcor 7140.000
taroff 7866.000
thafen 8245.000
towmin 7450.000
valacu 8150.000
vicame 8360.000

As you can see, every species has an elevation associated with it, and we can use the rank order of elevation as the ordering variable.
vegtab(veg,spcord=spc.elev,min=40)
    sithys oryhym chrvis purtri carrss arcpat senmul ceamar symore berrep
1      0.0    0.0    0.0    0.0    0.5    1.0    0.0    0.5    1.0    1.0
2      0.0    0.0    0.0    0.0    0.5    0.5    0.5    0.0    0.5    0.0
3      0.0    0.0    0.0    0.0    0.5    1.0    0.5    0.5    0.5    0.5
4      0.0    0.0    0.0    0.0    0.5    1.0    0.5    0.5    0.5    1.0
5      0.0    0.0    0.0    0.5    1.0    4.0    0.5    0.5    0.5    0.5
.       .      .      .      .      .      .      .      .      .      .
.       .      .      .      .      .      .      .      .      .      .
.       .      .      .      .      .      .      .      .      .      .
156    0.0    0.0    0.0    0.5    0.0    0.5    0.5    0.0    0.5    0.0
157    0.0    0.0    0.0    0.5    0.0    0.0    0.0    0.0    0.5    0.0
158    0.0    0.0    0.0    0.0    0.0    0.5    0.0    0.0    0.5    0.0
159    0.0    0.5    0.0    0.5    0.0    0.0    0.0    0.0    0.0    0.0
160    0.0    0.0    0.0    0.0    0.0    0.5    0.0    0.0    0.0    0.0

The species are listed in order from low elevation to high for those species which occur at least 40 times. We can order the plots by the same variable and get a sorted listing from low elevation to high in both plot locations and species modes.
vegtab(veg,pltord=elev,spcord=spc.elev,min=40)
    sithys oryhym chrvis purtri carrss arcpat senmul ceamar symore berrep
89     2.0    0.5    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0
90     5.0    0.5    0.5    0.0    0.0    0.0    0.0    0.0    0.0    0.0
99     1.0    0.5    0.5    0.0    0.0    0.0    0.0    0.0    0.0    0.0
100    0.5    0.5    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0
101    0.5    0.5    0.5    0.0    0.0    0.0    0.0    0.0    0.0    0.0
.      .      .      .      .      .      .      .      .      .      .
.      .      .      .      .      .      .      .      .      .      .
.      .      .      .      .      .      .      .      .      .      .
46     0.0    0.0    0.0    1.0    0.5    0.5    0.5    1.0    0.5    0.5
58     0.5    0.5    0.0    0.5    0.5    4.0    0.5    0.0    0.5    0.0
61     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5    1.0
87     0.5    0.5    0.0    0.5    1.0    3.0    0.5    1.0    1.0    1.0
60     0.0    0.0    0.0    0.0    0.5    0.5    0.5    0.0    1.0    1.0

Notice how the non-zero values go along the diagonal.

If, for some reason, you want to reverse the order of plots or species, simply put a negative sign in front of the order variable. For example,

vegtab(veg,pltord=-elev,spcord=-spc.elev,min=40)
    pacmyr berrep symore ceamar senmul arcpat carrss purtri chrvis oryhym
60     0.5    1.0    1.0    0.0    0.5    0.5    0.5    0.0    0.0    0.0
87     0.5    1.0    1.0    1.0    0.5    3.0    1.0    0.5    0.0    0.5
61     0.5    1.0    0.5    0.0    0.0    0.0    0.0    0.0    0.0    0.0
58     0.5    0.0    0.5    0.0    0.5    4.0    0.5    0.5    0.0    0.5
46     0.0    0.5    0.5    1.0    0.5    0.5    0.5    1.0    0.0    0.0
.      .      .      .      .      .      .      .      .      .      .
.      .      .      .      .      .      .      .      .      .      .
.      .      .      .      .      .      .      .      .      .      .
100    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5
101    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5    0.5
99     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5    0.5
90     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5    0.5
89     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5

The order here is not a perfect mirror order (e.g. 100,101) due to ties in elevation.

We haven't introduced ordination yet (that comes in later labs). I'll assume, however, that you know what ordination is, and demonstrate ordering plots and species by ordination scores. In Lab 10 we'll study correspondence analysis (CA), which ordinates both plots and species centroids on the same axes. The syntax here will look unfamiliar, but assume that we have stored the CA results for axis I in ca.plt and ca.spc.

vegtab(veg,pltord=ca.plt,spcord=ca.spc,min=40)
    pacmyr berrep arcpat symore ceamar carrss purtri senmul oryhym sithys
9      0.5    1.0    0.0    0.5    0.0    0.5    0.0    0.0    0.0    0.0
26     0.5    0.5    1.0    1.0    0.5    0.0    0.0    0.0    0.0    0.0
22     0.0    0.5    0.5    0.5    0.0    0.0    0.0    0.0    0.0    0.0
13     0.5    0.5    0.5    0.5    0.5    0.5    0.0    0.0    0.0    0.0
45     0.5    0.5    4.0    0.5    0.5    0.5    0.5    0.0    0.0    0.0
.      .      .      .      .      .      .      .      .      .      .
.      .      .      .      .      .      .      .      .      .      .
.      .      .      .      .      .      .      .      .      .      .
92     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5    1.0
89     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5    2.0
97     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5    1.0
96     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5    1.0
95     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.5    0.5
94     0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0    0.0

Again, as we would expect, the non-zero values go along the diagonal. The species order is not too different from high to low elevation, but the plot order has changed quite a bit. With that teaser, we'll leave vegetation tables for now, and go to vegetation constancy, importance, and discrimination tables.

Constancy and Importance Tables

Even with the ability to subset and order vegetation tables, there is often simply too much information in such a table to visualize and understand. In addition, we often want to compare results from multiple tables, which is difficult with vegtab().

A simple alternative to summarize vegetation tables is a constancy table, which lists for each species the relative frequency of occurrence in a specified sets. Accordingly, the LabDSV library includes a function called const() which behaves similarly to vegtab(). For example

const(veg,rep(1,nrow(veg)),min=0.1)
        res
ameuta 0.14
arcpat 0.46
ceamar 0.36
cermon 0.20
chrvis 0.25
juncom 0.24
pacmyr 0.30

.    .
.    .
.    .
opueri 0.10
pedcan 0.21
pencae 0.12
senmul 0.46

The rep(1,nrow(veg)) arguments makes a vector of 1's as long as the number of rows in veg, so const(veg,rep(1,nrow(veg)),min=0.1) lists the relative frequency of all species which occur with a minimum constancy of 0.1 (10% of the sample plots).

Of much more interest, of course, is to analyze specific variables for effect on the relative frequencies. For example, to look at topographic position,

const(veg,site$pos,min=0.1)  bottom low_slope mid_slope ridge up_slope ameuta 0.10 0.12 0.22 0.05 0.11 arcpat 0.20 0.45 0.53 0.66 0.40 arttri 0.00 0.09 0.11 0.05 0.14 atrcan 0.00 0.06 0.11 0.00 0.14 ceamar 0.10 0.30 0.53 0.55 0.22 cermon 0.25 0.24 0.12 0.22 0.25 . . . . . . . . . . . . . . . . . . sphcoc 0.05 0.06 0.14 0.00 0.05 steten 0.00 0.00 0.05 0.11 0.00 swerad 0.00 0.18 0.20 0.22 0.11 taroff 0.15 0.06 0.00 0.00 0.00 tradub 0.10 0.09 0.05 0.00 0.05  In this case, min=0.1 means that a species must achieve a relative frequency of 0.1 in at least one column. Constancy is not sensitive to abundance, but rather uses only presence/absence as its criterion. To look at the relative importance of a species, you can use a function called importance() that calculates the average value of a species when it's present (not averaging in the zeroes) in a set. For example, importance(veg,site$pos,min=0.1)
       bottom low_slope mid_slope ridge up_slope
ameuta   0.05      0.06      0.13  0.02     0.05
arcpat   0.47      1.09      1.56  1.33     0.72
arttri   0.00      0.16      0.24  0.02     0.15
atrcan   0.00      0.06      0.16  0.00     0.14
.       .         .         .     .        .
oenlav   0.12      0.18      0.05  0.00     0.01
pedcan   0.05      0.06      0.12  0.22     0.10
pencae   0.05      0.13      0.06  0.05     0.00
senmul   0.22      0.24      0.27  0.22     0.17
swerad   0.00      0.09      0.10  0.11     0.05

Because the matrix veg has values between 0 and 6, the "importance" calculated is an average cover code. Way back in Lab 1 were created a matrix of cover midpoints. To get an average cover by species we can use that matrix instead.
importance(cover,site$pos,min=1.0)  bottom low_slope mid_slope ridge up_slope arcpat 5.77 14.46 21.93 15.72 7.88 arttri 0.00 1.60 2.08 0.02 1.20 atrcan 0.00 0.18 1.00 0.00 0.62 ceamar 0.05 0.45 0.86 1.36 0.60 chrpar 0.02 1.01 0.00 0.00 0.02 chrvis 1.77 0.37 0.48 0.02 0.21 juncom 0.00 0.13 1.24 0.23 1.74 purtri 0.22 0.33 1.55 2.63 0.78 quegam 3.95 1.22 0.02 0.86 0.21 symore 0.10 0.22 0.44 1.05 0.51 artarb 6.45 7.65 3.62 1.66 1.38 artfri 1.65 0.06 0.00 0.00 0.01 berrep 0.05 0.40 0.75 0.63 1.55 ericor 0.00 0.00 0.00 0.00 1.05 agrsmi 2.67 0.04 0.08 0.00 0.44 broano 1.70 0.04 0.02 0.00 0.00 carrss 4.10 0.56 0.56 0.61 0.37 junbal 1.37 0.01 0.00 0.00 0.00 poanev 3.40 0.03 0.00 0.00 0.01 poapra 2.07 0.54 0.00 0.00 0.00 sithys 0.07 0.65 2.02 0.02 0.61 sticom 6.32 2.80 1.31 0.83 0.88  Here I asked for a minimum of 1.0, which would be an average cover of at least one percent, so few species qualified. Cover class midpoints almost always result in an overestimate of mean cover due to uneven distributions within classes, but that's a more complicated issue than we want to get into here. Somewhat like vegtab, we can order the species in the table with the spcord= argument. importance(cover,site$pos,min=1.0,spcord=spc.pres)
       bottom low_slope mid_slope ridge up_slope
carrss   4.10      0.56      0.56  0.61     0.37
symore   0.10      0.22      0.44  1.05     0.51
arcpat   5.77     14.46     21.93 15.72     7.88
berrep   0.05      0.40      0.75  0.63     1.55
purtri   0.22      0.33      1.55  2.63     0.78
ceamar   0.05      0.45      0.86  1.36     0.60
sithys   0.07      0.65      2.02  0.02     0.61
chrvis   1.77      0.37      0.48  0.02     0.21
juncom   0.00      0.13      1.24  0.23     1.74
artarb   6.45      7.65      3.62  1.66     1.38
sticom   6.32      2.80      1.31  0.83     0.88
quegam   3.95      1.22      0.02  0.86     0.21
arttri   0.00      1.60      2.08  0.02     1.20
artfri   1.65      0.06      0.00  0.00     0.01
agrsmi   2.67      0.04      0.08  0.00     0.44
atrcan   0.00      0.18      1.00  0.00     0.62
broano   1.70      0.04      0.02  0.00     0.00
poanev   3.40      0.03      0.00  0.00     0.01
junbal   1.37      0.01      0.00  0.00     0.00
chrpar   0.02      1.01      0.00  0.00     0.02
poapra   2.07      0.54      0.00  0.00     0.00
ericor   0.00      0.00      0.00  0.00     1.05


Finally, we can combine the constancy and mean abundance estimates in a single table with the concov() command.

concov(cover,site$pos)  bottom low_slope mid_slope ridge up_slope ameuta 10( 0.5) 12( 0.5) 22( 1.7) 6( 0.5) 11( 0.5) arcpat 20( 28.9) 45( 31.8) 54( 40.8) 67( 23.6) 40( 19.7) arttri 0( 0.0) 9( 17.7) 11( 18.8) 6( 0.5) 14( 8.4) atrcan 0( 0.0) 6( 3.0) 11( 9.0) 0( 0.0) 14( 4.4) ceamar 10( 0.5) 30( 1.5) 54( 1.6) 56( 2.5) 23( 2.6) cermon 25( 1.5) 24( 1.8) 13( 1.6) 22( 4.1) 26( 3.8) . . . . . . . . . . . . . . . . . . steten 0( 0.0) 0( 0.0) 6( 0.5) 11( 0.5) 0( 0.0) swerad 0( 0.0) 18( 0.5) 20( 0.5) 22( 0.5) 11( 0.5) taroff 15( 0.5) 6( 0.5) 0( 0.0) 0( 0.0) 0( 0.0) tradub 10( 0.5) 9( 0.5) 6( 5.3) 0( 0.0) 6( 0.5)  where the number in front of the parantheses is the constancy, and the number inside of the parentheses is the typical cover (not averaging in zeros). If you wnat the true mean cover (averaging in the zeros) you can say typical=FALSE concov(cover,site$pos,typical=FALSE)
          bottom low_slope mid_slope     ridge  up_slope
ameuta 10(  0.1) 12(  0.1) 22(  0.4)  6(  0.0) 11(  0.1)
arcpat 20(  5.8) 45( 14.5) 54( 21.9) 67( 15.7) 40(  7.9)
arttri  0(  0.0)  9(  1.6) 11(  2.1)  6(  0.0) 14(  1.2)
atrcan  0(  0.0)  6(  0.2) 11(  1.0)  0(  0.0) 14(  0.6)
ceamar 10(  0.1) 30(  0.5) 54(  0.9) 56(  1.4) 23(  0.6)
cermon 25(  0.4) 24(  0.4) 13(  0.2) 22(  0.9) 26(  1.0)
.         .         .         .         .         .
.         .         .         .         .         .
.         .         .         .         .         .
swerad  0(  0.0) 18(  0.1) 20(  0.1) 22(  0.1) 11(  0.1)
taroff 15(  0.1)  6(  0.0)  0(  0.0)  0(  0.0)  0(  0.0)
tradub 10(  0.1)  9(  0.1)  6(  0.3)  0(  0.0)  6(  0.0)


Species Discrimination Tables

Part of the objective of constancy and importance tables is to look for species which have high constancy or importance in some sets but low in others. You can find these by eye in the tables above (e.g. broano in the importance tables), but it's easier to find them algorithmically using the function spcdisc(). spcdisc calculates the total constancy or importance of a species in a table, and then calculates a statistic based on the Shannon-Weiner index. Species which are uniform across sets have a discrimination of 0.0, and species with all their constancy or importance in a single set have a discrimination of 1.0, and all other species scale in between depending on the concentration of their distribution among types.

To use spcdisc(), you give it the output from const() or importance(). For example

tmp <- const(veg,site$pos,min=0.1) spcdisc(tmp) [,1] ameuta 0.063969572 arcpat 0.038882521 arttri 0.175806493 atrcan 0.351017747 ceamar 0.089224478 cermon 0.018340996 . . . . . . senmul 0.007185067 sphcoc 0.207918437 steten 0.614097338 swerad 0.157004684 taroff 0.628274204 tradub 0.169632400  Of the abbreviated list given here, steten and taroff (dandelion) have the highest discrimination. To highlight the best species, use the sort=TRUE argument. spcdisc(tmp,sort=TRUE)  [,1] irimis 1.000000000 muhric 1.000000000 ericor 1.000000000 junbal 0.810718950 lupkin 0.720050581 astagr 0.720050581 . . . . . . eupfen 0.027258931 carrss 0.022793540 cermon 0.018340996 lotuta 0.008907766 senmul 0.007185067  The first three species are perfect discriminators of topographic position, followed by several other good ones. The bottom of the list are either ubiquitous species (e.g. carrss and senmul) or indiscriminant species. We haven't covered cluster analysis yet (we'll get to it about Lab 13), but I'm sure you can imagine using such a function to determine the diagnostic species of clusters. For example, assume that clusid contains the cluster membership of each plot in one of ten clusters. Then, spcdisc(const(veg,clusid,min=0.1),sort=TRUE)  [,1] towmin 1.0000000 strcor 1.0000000 stapin 1.0000000 salibe 1.0000000 oenfla 1.0000000 oencor 1.0000000 molpar 1.0000000 lyggra 1.0000000 lupser 1.0000000 lupkin 1.0000000 leppun 1.0000000 ivesab 1.0000000 irimis 1.0000000 heddru 1.0000000 genaff 1.0000000 eriumb 1.0000000 erisub 1.0000000 echtri 1.0000000 dessop 1.0000000 asthum 1.0000000 astchi 1.0000000 artcar 1.0000000 stipin 1.0000000 muhric 1.0000000 hiljam 1.0000000 agrscr 1.0000000 agrcri 1.0000000 atrcon 1.0000000 arcuva 1.0000000 sherot 1.0000000 chrdep 1.0000000 junbal 0.9354261 eripan 0.9048754 . . . . . .  gives us a list of diagnostic species. Notice how I embedded the call to const() inside of spcdisc() rather than saving it as a temporary object. Using Vegetation Tables As you can see in this lab, you can use vegetation tables directly to study vegetation, and there is a long history of such work in vegetation ecology. It seems to me, however, that its greatest utility is in determining the details of results from quantitative analyses we will cover in the rest of the labs. Accordingly, we'll leave vegetation tables for a while, but you'll see their use again in subsequent labs. Functions Used in This Lab vegtab() vegtab <- function (taxa, set, minval = 1, pltord, spcord, pltlbl, trans = FALSE) { if (missing(set)) { set <- seq(1:nrow(taxa)) } else { set <- seq(1:nrow(taxa))[set] set <- set[!is.na(set)] } tmp <- taxa[set, ] spcidx <- apply(tmp > 0, 2, sum) tmp <- tmp[, spcidx >= minval] if (missing(pltord)) { pltord <- seq(1:nrow(tmp)) } else { pltord <- pltord[set] } if (missing(spcord)) { spcord <- -apply(tmp > 0, 2, sum) } else { spcord <- spcord[spcidx >= minval] } if (!missing(pltlbl)) { if (is.numeric(pltlbl)) { tmp <- cbind(pltlbl[set], tmp) dimnames(tmp)[[2]][1] <- deparse(substitute(pltlbl)) spcord <- c(min(spcord) - 1, spcord) } else { dimnames(tmp)[[1]] <- pltlbl } } tmp <- tmp[order(pltord), order(spcord)] if (trans == TRUE) { tmp <- t(tmp) } tmp }  const() const function (taxa, clustering, minval = 0, show = minval, digits = 2, sort = FALSE, spcord = NULL) { if (inherits(clustering, c("partana", "partition", "clustering"))) clustering <- clustering$clustering
namlst <- NULL
if (!is.data.frame(taxa))
taxa <- data.frame(taxa)
if (missing(clustering))
clustering <- rep(1, nrow(taxa))
clustering <- clustering[!is.na(clustering)]
if (is.factor(clustering)) {
namlst <- levels(clustering)
clustering <- as.integer(clustering)
}
else if (is.numeric(clustering)) {
namlst <- as.integer(levels(factor(clustering)))
}
if (is.vector(clustering)) {
res <- matrix(0, nrow = ncol(taxa), ncol = max(clustering))
x <- apply(taxa, 2, function(x) {
tapply(x > 0, clustering, sum)
})
y <- as.numeric(table(clustering))
res <- x/y
keep <- as.logical(apply(res, 2, max) >= minval)
res <- res[, keep]
tmp <- as.data.frame(t(res))
row.names(tmp) <- names(taxa)[keep]
if (!is.null(spcord)) {
tmp <- tmp[rev(order(spcord[keep])), ]
}
}
if (!is.null(namlst))
names(tmp) <- namlst
tmp <- format(round(tmp, digits = digits))
tmp[tmp < show] <- substring(" .  ", 1, digits + 2)
if (sort) {
print(tmp)
repeat {
plots <- readline(" enter the species: ")
if (plots == "")
break
else pnt <- readline(" in front of        : ")
for (i in (strsplit(plots, ",")[[1]])) {
ord <- 1:nrow(tmp)
x <- match(i, row.names(tmp))
if (!is.na(x)) {
z <- ord[x]
ord <- ord[-x]
y <- match(pnt, row.names(tmp))
if (!is.na(y)) {
if (y > 1) {
first <- ord[1:(y - 1)]
last <- ord[y:length(ord)]
ord <- c(first, z, last)
}
else {
last <- ord[y:length(ord)]
ord <- c(z, last)
}
tmp <- tmp[ord, ]
print(tmp)
}
else {
print(paste("species", pnt, "does not exist"))
}
}
else {
print(paste("species", i, "does not exist"))
}
}
}
return(tmp)
}
else {
return(tmp)
}
}


importance()

importance
function (taxa, clustering, minval = 0, digits = 2, show = minval,
sort = FALSE, typical = TRUE, spcord)
{
if (inherits(clustering, c("partana", "partition", "clustering")))
clustering <- clustering$clustering namlst <- NULL if (!is.data.frame(taxa)) taxa <- data.frame(taxa) if (missing(clustering)) clustering <- rep(1, nrow(taxa)) clustering <- clustering[!is.na(clustering)] if (is.factor(clustering)) { namlst <- levels(clustering) clustering <- as.integer(clustering) } else if (is.numeric(clustering)) { namlst <- as.integer(levels(factor(clustering))) } if (is.vector(clustering)) { res <- matrix(0, nrow = ncol(taxa), ncol = max(clustering)) x <- apply(taxa, 2, function(x) { tapply(x, clustering, sum) }) if (typical) y <- apply(taxa, 2, function(x) { tapply(x > 0, clustering, sum) }) else y <- apply(taxa, 2, function(x) { tapply(x >= 0, clustering, sum) }) y[x == 0] <- 1 res <- x/y keep <- as.logical(apply(res, 2, max) >= minval) res <- res[, keep] tmp <- as.data.frame(t(res)) row.names(tmp) <- names(taxa)[keep] if (!missing(spcord)) { tmp <- tmp[rev(order(spcord[keep])), ] } } if (!is.null(namlst)) names(tmp) <- namlst tmp <- format(round(tmp, digits = digits)) tmp[tmp < show] <- substring(" . ", 1, nchar(tmp[1, 1])) if (sort) { cat("\nConstancy Table\n\n") print(tmp) repeat { plots <- readline(" enter the species: ") if (plots == "") break else pnt <- readline(" in front of : ") for (i in (strsplit(plots, ",")[[1]])) { ord <- 1:nrow(tmp) x <- match(i, row.names(tmp)) if (!is.na(x)) { ord <- ord[-x] y <- match(pnt, row.names(tmp[ord, ])) if (!is.na(y)) { if (y == 1) { ord <- c(x, ord) } else { first <- ord[1:(y - 1)] last <- ord[y:length(ord)] ord <- c(first, x, last) } tmp <- tmp[ord, ] print(tmp) } else { print(paste("species", pnt, "does not exist")) } } else { print(paste("species", i, "does not exist")) } } } return(tmp) } else { return(tmp) } }  concov() concov <- function (taxa, clustering, digits = 1, width = 5, typical = TRUE, thresh = 10) { if (inherits(clustering, c("clustering", "partana", "pam"))) clustering <- clustering$clustering
x <- const(taxa, clustering)
y <- importance(taxa, clustering, typical = typical)
tmp <- NULL
keep <- apply(as.matrix(x), 1, max) >= thresh/100
for (i in 1:length(table(clustering))) {
a <- formatC(as.numeric(x[, i]) * 100, width = 2, format = "d")
b <- formatC(as.numeric(y[, i]), width = width, digits = digits,
format = "f")
tmp <- cbind(tmp, paste(a, "(", b, ")", sep = ""))
}
tmp <- tmp[keep, ]
tmp <- data.frame(tmp)
row.names(tmp) <- names(taxa)[keep]
names(tmp) <- as.character(levels(factor(clustering)))
tmp
}


spcdisc()

spcdisc <- function (x, sort = FALSE)
{
shannon <- function(y) {
frac <- y/sum(y)
comp <- sum((-1 * frac * log(frac))[frac > 0])
comp <- 1 - (comp/log(length(y)))
comp
}
tmp <- apply(x, 1, shannon)
if (sort)
tmp <- tmp[rev(order(tmp))]
tmp
}