GIFT tutorial

Pierre Denelle & Patrick Weigelt

2023-03-14


The Global Inventory of Floras and Traits (GIFT) is a database of floras and plant checklists, distributed worldwide. It also includes trait and phylogenetic information. The GIFT R package grants an access to the GIFT database.
This vignette illustrates the most common usages of the package through detailed examples.

  1. Retrieving plant checklists within a given area (example: Mediterranean)
  2. Getting the distribution of a plant species
  3. Retrieving trait information for a subset of plant species
  4. Retrieving environmental information for a list of polygons/regions
  5. Retrieving a plant phylogeny and plotting a trait coverage on it


The following R packages are needed to build this vignette:

library("GIFT")
library("dplyr")
library("ggplot2")
library("sf")
library("rnaturalearth")
library("rnaturalearthdata")
library("tidyr")
library("patchwork")



1. Checklists for a region

1.1. Shapefile

Let’s assume we are interested in having a floristic knowledge of the western part of the Mediterranean basin. For this purpose, we can simply use a shape file of the region of interest and feed it to the GIFT_checklists() function.

We do provide a shape file of this region in the GIFT R package, which you can access using the data("western_mediterranean") command.

data("western_mediterranean")

world <- ne_coastline(scale = "medium", returnclass = "sf")
world_countries <- ne_countries(scale = "medium", returnclass = "sf")
# Fixing polygons crossing dateline
world <- st_wrap_dateline(world)
world_countries <- st_wrap_dateline(world_countries)

# Eckert IV projection
eckertIV <-
  "+proj=eck4 +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"

ggplot(world) +
  geom_sf(color = "gray50") +
  geom_sf(data = western_mediterranean, fill = "darkblue", color = "black",
          alpha = 0.5, size = 1) +
  labs(title = "Western Mediterranean basin") +
  lims(x = c(-20, 20), y = c(24, 48)) +
  theme_void()


Please note that shapes used in GIFT are unprojected (Geographic Coordinate System WGS84), and that all shapefiles provided should be in this CRS. You can check the coordinate reference system of a sf object by using sf::st_crs().

1.2. Main arguments

Now that we have a shape for the region of interest, let’s call GIFT_checklists(). This wrapper function has many arguments which we detail in this subsection.
First, the taxonomic group of interest. We can be interested in a particular group of plants, for example only Angiosperms. In that case, we would set the taxon_name argument like this taxon_name = "Angiospermae". If we are interested in a particular plant family, let’s say orchids, then taxon_name = "Orchidaceae".
To see all options for the taxon_name argument, you can run the GIFT_taxonomy() function and look at the taxon_name column of its output.
Together with this first argument comes complete_taxon. This argument, set by default to TRUE defines whether only regions represented by checklists in GIFT completely covering the taxon of interest should be retrieved. Figure 1 is explaining the principle.

Figure 1. Principle of the complete_taxon argument

Figure 1. Principle of the complete_taxon argument


In Figure 1, we want to retrieve checklists of Angiosperms. In the first region available, region A only one checklist is of interest. This checklist is then always retrieved. In region B, there is only a checklist of orchids, which is a subset only of Angiosperms. If complete_taxon is set to TRUE, then this checklist won’t be retrieved, otherwise yes. Finally, in region C, there is a checklist of vascular plants and one for orchids. In both cases, the checklist of vascular plants will be retrieved after filtering out the non-angiosperm species. The species of Orchids is also retrieved in both cases as it is not the only one available and as it can complete the floristic knowledge for Angiosperms in this region.

Following arguments of GIFT_checklists() relate to the floristic statuses of plant species. We can for example only be interested in endemic species, or naturalized species. Default value is retrieving all native species.
Similarly, two arguments are needed in the function. First, floristic_group defines the group of interest. Second, complete_floristic states whether incomplete regions regarding the floristic group chosen should be retrieved or not. The logic is detailed in Figure 2 and is similar to the complete_taxon argument shown before.


Figure 2. Principle of the complete_floristic argument

Figure 2. Principle of the complete_floristic argument


The next set of arguments relate to spatial matching between the desired area and the GIFT database.

The main argument in that regard, when providing a shapefile or a set of coordinates, is the overlap argument. This argument can get 4 options, each of these options leading to a different outcome as explained in Figure 3.

Figure 3. Principle of GIFT_spatial()

Figure 3. Principle of GIFT_spatial()


On Figure3, the GIFT polygons represented in orange either intersect, fall inside or outside the provided shape file. The overlap argument below each GIFT polygon illustrates in which situation a given GIFT polygon is retrieved or not.


Another important spatial feature we provide is the possibility to remove overlapping polygons. Indeed, for many regions in the world, there are several polygons in GIFT database that cover them. If overlapping polygons are not an issue for your case study, you can simply set remove_overlap to FALSE (top right part of Figure 4). But in case you want one polygon only per region, then remove_overlap can be set to TRUE. In that case, the GIFT_checklists() will either retrieve the smaller or the larger polygon. This will depend on the values set for the argument area_threshold_mainland as detailed in Figure 4.

Figure 4. Removing overlapping polygons with remove_overlap argument

Figure 4. Removing overlapping polygons with remove_overlap argument


area_threshold_mainland takes a value in \(km^2\). In case the area of the smaller polygon is below the threshold, then the larger overlapping polygon will be retrieved (bottom left part in Figure 4). If the smaller polygon exceeds that threshold, then it will be retrieved (bottom right part of Figure 4). There is a similar argument for islands, area_threshold_island, which is by default set to 0 \(km^2\). That way, by default, the smaller islands are always retrieved.

Please also note that polygons are considered as overlapping when the exceed a certain percentage of overlap. This percentage can be modified using the overlap_threshold argument (Figure 5). This argument is set by default to 10%.

Figure 5. Principle of the overlap_th argument

Figure 5. Principle of the overlap_th argument


1.3. GIFT_checklists()

Now that we covered the main arguments of GIFT_checklists(), we can retrieve plant checklists for the Mediterranean region. GIFT_checklists() returns a list of two elements. First the metadata of checklists fulfilling the different criteria, named $lists. The second element is a data.frame of all the checklists with the species composition per checklist ($checklists).
If you only want to retrieve the metadata, you can set the argument list_set_only to TRUE.

ex_meta <- GIFT_checklists(taxon_name = "Angiospermae",
                           shp = western_mediterranean,
                           overlap = "centroid_inside",
                           list_set_only = TRUE)


And to retrieve the species composition:

medit <- GIFT_checklists(taxon_name = "Angiospermae",
                         complete_taxon = TRUE,
                         floristic_group = "native",
                         complete_floristic = TRUE,
                         geo_type = "All",
                         shp = western_mediterranean,
                         overlap = "centroid_inside", 
                         remove_overlap = FALSE,
                         taxonomic_group = TRUE) # this argument adds two
# columns to the checklist: plant family and taxonomic group of each species


We can now have an estimation on the number of checklists with native Angiosperm species in the western part of the Mediterranean basin, as well as of the number of species.

# Number of references covered
length(unique(medit[[2]]$ref_ID))
#   22 references

# Number of checklists covered (one reference can have several lists inside)
length(unique(medit[[2]]$list_ID))
#   115 checklists

# Number of species
length(unique(medit[[2]]$work_species))
#   12840 plant species


You can now apply different values for the arguments detailed above. When being stricter with some criteria, you can see that the number of checklists retrieved decreases. For example, when removing overlapping regions:

medit_no_overlap <- GIFT_checklists(shp = western_mediterranean,
                                    overlap = "centroid_inside",
                                    taxon_name = "Angiospermae",
                                    remove_overlap = TRUE)

# Number of references covered
length(unique(medit[[2]]$ref_ID)) # 23 references
length(unique(medit_no_overlap[[2]]$ref_ID)) # 22 references

Please note that the function not only works with a shape file but can accept a set of coordinates. The example below illustrates a case in which you want to retrieve GIFT checklists intersecting the coordinates of Göttingen.

custom_point <- cbind(9.9, 51) # coordinates of Göttingen

got <- GIFT_checklists(coordinates = custom_point,
                       overlap = "extent_intersect",
                       taxon_name = "Angiospermae",
                       remove_overlap = TRUE,
                       list_set_only = TRUE)



To cite properly the references retrieved, you can run the function GIFT_references() and look for the column ref_long``. The column alsogeo_entity_ref` associates each reference to a name.


1.4. Species richness map

Once we downloaded a set of checklists, it is possible to map the species richness of the taxonomic group of interest. For this purpose, we use a combination of two functions: GIFT_richness() which either retrieves species richness or trait coverage per polygon and GIFT_shapes() which retrieves the shapefile of a list of GIFT polygons.
The next two chunks illustrate this for the Angiosperms in the World and in the Western part of the Mediterranean basin.

gift_shapes <- GIFT_shapes() # retrieves all shapefiles by default
angio_rich <- GIFT_richness(taxon_name = "Angiospermae")

rich_map <- dplyr::left_join(gift_shapes, angio_rich, by = "entity_ID") %>%
  dplyr::filter(stats::complete.cases(total))

ggplot(world) +
  geom_sf(color = "gray50") +
  geom_sf(data = rich_map, aes(fill = total + 1)) +
  scale_fill_viridis_c("Species number\n(log-transformed)", trans = "log10",
                       labels = scales::number_format(accuracy = 1)) +
  labs(title = "Angiosperms", subtitle = "Projection EckertIV") +
  coord_sf(crs = eckertIV) +
  theme_void()


By customizing the code above, you can also produce a nicer map:


Below is the R code to produce the above map if interested.

Fancier code
# Background box
xmin <- st_bbox(world)[["xmin"]]; xmax <- st_bbox(world)[["xmax"]]
ymin <- st_bbox(world)[["ymin"]]; ymax <- st_bbox(world)[["ymax"]]
bb <- sf::st_union(sf::st_make_grid(st_bbox(c(xmin = xmin,
                                              xmax = xmax,
                                              ymax = ymax,
                                              ymin = ymin),
                                            crs = st_crs(4326)),
                                    n = 100))

# Equator line
equator <- st_linestring(matrix(c(-180, 0, 180, 0), ncol = 2, byrow = TRUE))
equator <- st_sfc(equator, crs = st_crs(world))

ggplot(world) +
  geom_sf(data = bb, fill = "aliceblue") +
  geom_sf(data = equator, color = "gray50", linetype = "dashed",
          linewidth = 0.1) +
  geom_sf(data = world_countries, fill = "antiquewhite1", color = NA) +
  geom_sf(color = "gray50", linewidth = 0.1) +
  geom_sf(data = bb, fill = NA) +
  geom_sf(data = rich_map,
          aes(fill = ifelse(rich_map$entity_class %in%
                              c("Island/Mainland", "Mainland",
                                "Island Group", "Island Part"),
                            total + 1, NA)),
          size = 0.1) +
  geom_point(data = rich_map,
             aes(color = ifelse(rich_map$entity_class %in%
                                  c("Island"),
                                total + 1, NA),
                 geometry = geometry),
             stat = "sf_coordinates", size = 1, stroke = 0.5) +
  scale_color_gradientn(
    "Species number", trans = "log10", limits = c(1, 40000), 
    colours = RColorBrewer::brewer.pal(5, name = "Greens"),
    breaks = c(1, 10, 100, 1000, 10000, 40000),
    labels = c(1, 10, 100, 1000, 10000, 40000),
    na.value = "transparent") +
  scale_fill_gradientn(
    "Species number", trans = "log10", limits = c(1, 40000), 
    colours = RColorBrewer::brewer.pal(5, name = "Greens"),
    breaks = c(1, 10, 100, 1000, 10000, 40000),
    labels = c(1, 10, 100, 1000, 10000, 40000),
    na.value = "transparent") +
  labs(title = "Angiosperms", subtitle = "Projection EckertIV") +
  coord_sf(crs = eckertIV) +
  theme_void()



We can also produce maps of richness at intermediate scales. Here is the code and the map of Angiosperms in the Western Mediterranean basin.

med_shape <- gift_shapes[which(gift_shapes$entity_ID %in% 
                                 unique(medit[[2]]$entity_ID)), ]

med_rich <- angio_rich[which(angio_rich$entity_ID %in% 
                               unique(medit[[2]]$entity_ID)), ]

med_map <- dplyr::left_join(med_shape, med_rich, by = "entity_ID") %>%
  dplyr::filter(stats::complete.cases(total))

ggplot(world) +
  geom_sf(color = "gray50") +
  geom_sf(data = western_mediterranean,
          fill = "darkblue", color = "black", alpha = 0.1, size = 1) +
  geom_sf(data = med_map, aes(fill = total)) +
  scale_fill_viridis_c("Species number") +
  labs(title = "Angiosperms in the Western Mediterranean basin") +
  lims(x = c(-20, 20), y = c(24, 48)) +
  theme_void()



2. Distribution of species

The GIFT R package also allows for retrieving the spatial distribution of a focal plant species.

2.1. Available species

To know what plant species are available, you can first run the function GIFT_species().

all_sp <- GIFT_species()

364571 species are currently available in the database. This number may increase with new releases of the database. See the dedicated section in the advanced vignettes for more details.

2.2. Species names and taxonomic harmonization

Since GIFT is a collection of checklists in which authors use their own taxonomic knowledge to describe species, there is a step of taxonomic harmonization when including checklists into the database. The most frequent backbone used is the World Checklists of Vascular Plants (WCVP).
Both original and harmonized names are stored in the database and you can use the function GIFT_species_lookup() to look at the differences for particular species. For example, the wood anemone Anemone nemorosa.

anemone_lookup <- GIFT_species_lookup(genus = "Anemone", epithet = "nemorosa")

kable(anemone_lookup, "html") %>%
  kable_styling(full_width = FALSE)
name_ID genus species_epithet subtaxon author matched epithetscore overallscore resolved synonym matched_subtaxon accepted service work_ID taxon_ID work_genus work_species_epithet work_species work_author
3718 Anemone nemorosa NA NA 1 1 0.8421053 1 NA NA NA tpl 2293 1303 Anemone nemorosa Anemone nemorosa NA
3719 Anemone nemorosa NA L. 1 1 1.0000000 1 NA NA NA tpl 2293 1303 Anemone nemorosa Anemone nemorosa NA
526917 Anemonoides nemorosa NA (L.) Holub 1 1 1.0000000 1 NA NA NA tpl 2293 1303 Anemone nemorosa Anemone nemorosa NA
772823 Anemonoides nemorosa NA NA 1 1 0.6451613 1 NA NA NA tpl 2293 1303 Anemone nemorosa Anemone nemorosa NA

Looking at the output table, you can see the original species names and their identification numbers (name_ID) before taxonomic harmonization. The species’ names and IDs after taxonmic harmonization are the last columns on the right starting with the prefix work_.



2.3. Species distribution


Now that we have a focal species and its harmonized name, we can retrieve its distribution using GIFT_species_distribution().
Please note that we here set the aggregation argument to TRUE in order to have only one floristic status per polygon. For further details, check the help page of the function.

anemone_distr <- GIFT_species_distribution(
  genus = "Anemone", epithet = "nemorosa", aggregation = TRUE)

anemone_statuses <- anemone_distr %>%
  mutate(native = ifelse(native == 1, "native", "non-native"),
         naturalized = ifelse(naturalized == 1, "naturalized",
                              "non-naturalized"),
         endemic_list = ifelse(endemic_list == 1, "endemic_list",
                               "non-endemic_list")) %>%
  dplyr::select(entity_ID, native, naturalized, endemic_list)

table(anemone_statuses$endemic_list)
## 
## non-endemic_list 
##               53

This species is not listed as endemic in any of the GIFT polygons. Let’s now check the places where it is listed as native or naturalized.

table(paste(anemone_statuses$native, anemone_statuses$naturalized,
            sep = "_"))
## 
##                      NA_NA                  native_NA 
##                         13                         17 
##     native_non-naturalized              non-native_NA 
##                        113                          3 
##     non-native_naturalized non-native_non-naturalized 
##                          5                          2

Looking at the different combinations of statuses, we can distinguish several situations: in 13 polygons, there is no status available. The species is listed as native and non-naturalized (or naturalized status is missing) in 113+17=130 polygons. It is naturalized and non native in 5 polygons.
More surprising are the cases where the species is non-native and non-naturalized, which happens in 3+2=5 polygons. This specific combination can happen in unstable cases where the species in the process of being naturalized.

Now that we know in which polygons the species occur and with what status, we can map its distribution using the GIFT shapes we retrieved earlier using GIFT_shapes().

# We rename the statuses based on the distinct combinations
anemone_statuses <- anemone_statuses %>%
  mutate(Status = case_when(
    native == "native" & naturalized == "non-naturalized" ~ "native",
    native == "native" & is.na(naturalized) ~ "native",
    native == "non-native" & is.na(naturalized) ~ "non-native",
    native == "non-native" & naturalized == "naturalized" ~ "naturalized",
    native == "non-native" & naturalized == "non-naturalized" ~ "non-native",
    is.na(native) & is.na(naturalized) ~ "unknown"
  ))

# Merge with the shapes
anemone_shape <- gift_shapes[which(gift_shapes$entity_ID %in% 
                                     unique(anemone_distr$entity_ID)), ]
anemone_map <- dplyr::left_join(anemone_shape, anemone_statuses,
                                by = "entity_ID")

# Area of distribution with floristic status
ggplot(world) +
  geom_sf(color = "gray70") +
  geom_sf(data = anemone_map, color = "black", aes(fill = as.factor(Status))) +
  scale_fill_brewer("Status", palette = "Set2") +
  labs(title = expression(paste("Distribution map of ",
                                italic("Anemone nemorosa"))),
       subtitle = "Unprojected (GCS: WGS84)") +
  lims(x = c(-65, 170), y = c(-45, 70)) +
  theme_void()