Growth forms coverage#

We extracted growth form information (tree/shrub/herb) from TRY (Trait-ID 42) to each iNaturalist observation and estimated the coverage of each growth form for all sPlotOpen plots. We chose the most commonly used classification for each species. The average tree/shrub/herb coverage was then calculated for each grid cell and the these means correlated.

This section covers:

  • Link growth form information to iNaturalist observations

  • Calculate coverage

  • Plot coverage

  • Compare to sPlot life form coverage

# packages
import os
import pandas as pd
import numpy as np

from matplotlib import pyplot as plt
import seaborn as sns
import matplotlib.ticker as ticker
from matplotlib.colors import LogNorm, Normalize
from matplotlib.ticker import MaxNLocator
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from matplotlib.colors import BoundaryNorm

Calculate coverage#

plt.rcParams.update({'font.size': 15})

step = 181

bins_x = np.linspace(-180,180,step) 
bins_y= np.linspace(-90,90,int(((step - 1)/2)+1))
iNat_lf['x_bin'] = pd.cut(iNat_lf['decimalLongitude'], bins=bins_x)
iNat_lf['y_bin'] = pd.cut(iNat_lf['decimalLatitude'], bins=bins_y)
iNat_lf['x_bin'] = iNat_lf['x_bin'].apply(lambda x: x.left)
iNat_lf['y_bin'] = iNat_lf['y_bin'].apply(lambda x: x.left)
iNat_tree = iNat_lf[iNat_lf['life form']== "is_tree"]
iNat_shrub = iNat_lf[iNat_lf['life form']== "is_shrub"]
iNat_herb = iNat_lf[iNat_lf['life form']== "is_herb"]

First get number of observations per grid cell:

grouped_all = iNat_lf.groupby(['x_bin', 'y_bin'], as_index=False)['life form'].size()
grouped_all
x_bin y_bin size
0 -180.0 -90.0 0
1 -180.0 -88.0 0
2 -180.0 -86.0 0
3 -180.0 -84.0 0
4 -180.0 -82.0 0
... ... ... ...
16195 178.0 80.0 0
16196 178.0 82.0 0
16197 178.0 84.0 0
16198 178.0 86.0 0
16199 178.0 88.0 0

16200 rows × 3 columns

Then calcualte number of is_tree, is_shrub, and is_herb in each grid cell.

grouped_trees = iNat_tree.groupby(['x_bin', 'y_bin'], as_index=False)['life form'].size()
grouped_shrubs = iNat_shrub.groupby(['x_bin', 'y_bin'], as_index=False)['life form'].size()
grouped_herbs = iNat_herb.groupby(['x_bin', 'y_bin'], as_index=False)['life form'].size()
grouped_all['cover_tree'] = grouped_trees['size']/grouped_all['size']
grouped_all['cover_shrub'] = grouped_shrubs['size']/grouped_all['size']
grouped_all['cover_herb'] = grouped_herbs['size']/grouped_all['size']
grouped_all
x_bin y_bin size cover_tree cover_shrub cover_herb
0 -180.0 -90.0 0 NaN NaN NaN
1 -180.0 -88.0 0 NaN NaN NaN
2 -180.0 -86.0 0 NaN NaN NaN
3 -180.0 -84.0 0 NaN NaN NaN
4 -180.0 -82.0 0 NaN NaN NaN
... ... ... ... ... ... ...
16195 178.0 80.0 0 NaN NaN NaN
16196 178.0 82.0 0 NaN NaN NaN
16197 178.0 84.0 0 NaN NaN NaN
16198 178.0 86.0 0 NaN NaN NaN
16199 178.0 88.0 0 NaN NaN NaN

16200 rows × 6 columns

Plot coverage#

for lf in ['cover_tree', 'cover_shrub', 'cover_herb']:
    data_iNat_TRY = grouped_all.pivot('y_bin', 'x_bin', lf)
# data format
    data_crs = ccrs.PlateCarree()
    
    #for colorbar
    levels_iNat = MaxNLocator(nbins=15).tick_values(grouped_all[lf].min(), grouped_all[lf].max())
    cmap = plt.get_cmap('gist_yarg')
    norm = BoundaryNorm(levels_iNat, ncolors=cmap.N, clip=True)
    im_ratio = data_iNat_TRY.shape[0]/data_iNat_TRY.shape[1]

    #plot map
    fig = plt.figure(figsize=(15, 15)) # I created a new figure and set up its size

    #create base plot of a world map
    ax = fig.add_subplot(1, 1, 1, projection=ccrs.Robinson()) # I used the PlateCarree projection from cartopy
    ax.set_global()
    
    #add grid with values
    im = ax.pcolormesh(bins_x, bins_y, data_iNat_TRY, cmap="gist_yarg", 
                   vmin=grouped_all[lf].min(),
                  vmax=grouped_all[lf].max(),
                      transform=data_crs) 
    
    #add color bar
    label= 'percent observation' + lf
    fig.colorbar(im,fraction=0.046*im_ratio, pad=0.04, label=label )

    #add coastlines
    ax.coastlines(resolution='110m', color='black', linewidth=0.8)

    #set title
    ax.set_title( "iNaturalist " + lf, size=14)
    
    filename = '../Figures/iNat_' + lf[0:4] + '_cover.pdf'
    plt.savefig(filename, bbox_inches='tight')  

   
_images/Chapter_11_Growth_Forms_Coverage_32_0.png _images/Chapter_11_Growth_Forms_Coverage_32_1.png _images/Chapter_11_Growth_Forms_Coverage_32_2.png

Compare to sPlot life form coverage#

sPlot_cover = pd.read_csv("sPlotOpen/splot_cover_v1.csv") 
sPlot_cover
PlotObservationID lat long cover_tree cover_shrub cover_herb
0 16.0 62.420000 -154.180000 0.000000 0.000000 1.000000
1 17.0 62.420000 -154.180000 0.000000 0.000000 1.000000
2 18.0 62.420000 -154.180000 0.000000 0.000000 1.000000
3 20.0 62.420000 -154.180000 0.000000 0.000000 1.000000
4 22.0 62.420000 -154.180000 0.000000 0.025641 0.974359
... ... ... ... ... ... ...
95099 1126749.0 56.287870 27.273862 0.000000 0.142857 0.857143
95100 1126761.0 56.939965 23.598014 0.000000 0.010526 0.989474
95101 1126769.0 56.939965 23.598014 0.005025 0.045226 0.949749
95102 1126774.0 57.248222 22.147667 0.038462 0.230769 0.730769
95103 1126790.0 57.563967 26.892074 0.010460 0.194561 0.794979

95104 rows × 6 columns

plt.rcParams.update({'font.size': 15})

step = 181

bins_x = np.linspace(-180,180,step) 
bins_y= np.linspace(-90,90,int(((step - 1)/2)+1))
sPlot_cover['x_bin'] = pd.cut(sPlot_cover['long'], bins=bins_x)
sPlot_cover['y_bin'] = pd.cut(sPlot_cover['lat'], bins=bins_y)
sPlot_cover['x_bin'] = sPlot_cover['x_bin'].apply(lambda x: x.left)
sPlot_cover['y_bin'] = sPlot_cover['y_bin'].apply(lambda x: x.left)


for lf in ['cover_tree', 'cover_shrub', 'cover_herb']:

    sPlot_raster = sPlot_cover.groupby(['x_bin', 'y_bin'], as_index=False)[lf].mean()
    sPlot_lf_p = sPlot_raster.pivot('y_bin', 'x_bin', lf)
    # data format
    data_crs = ccrs.PlateCarree()
    
    #for colorbar
    levels= MaxNLocator(nbins=15).tick_values(sPlot_cover[lf].min(), sPlot_cover[lf].max())
    cmap = plt.get_cmap('gist_yarg')
    norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)
    im_ratio = sPlot_lf_p.shape[0]/sPlot_lf_p.shape[1]

    #plot map
    fig = plt.figure(figsize=(15, 15)) # I created a new figure and set up its size

    #create base plot of a world map
    ax = fig.add_subplot(1, 1, 1, projection=ccrs.Robinson()) # I used the PlateCarree projection from cartopy
    ax.set_global()
    
    #add grid with values
    im = ax.pcolormesh(bins_x, bins_y, sPlot_lf_p, cmap="gist_yarg", 
                   vmin=sPlot_raster[lf].min(),
                  vmax=sPlot_raster[lf].max(),
                      transform=data_crs) 
    
    #add color bar
    label= 'percent observation' + lf
    fig.colorbar(im,fraction=0.046*im_ratio, pad=0.04, label=label )

    #add coastlines
    ax.coastlines(resolution='110m', color='black', linewidth=0.8)

    #set title
    ax.set_title( "iNaturalist " + lf, size=14)
    
    filename = '../Figures/sPlot_' + lf + '_cover.pdf'
    plt.savefig(filename, bbox_inches='tight')  

   
_images/Chapter_11_Growth_Forms_Coverage_36_0.png _images/Chapter_11_Growth_Forms_Coverage_36_1.png _images/Chapter_11_Growth_Forms_Coverage_36_2.png
sPlot_raster = sPlot_cover.groupby(['x_bin', 'y_bin'], as_index=False)['cover_tree'].mean()

for lf in ['cover_shrub', 'cover_herb']:

    sPlot_raster[lf] = sPlot_cover.groupby(['x_bin', 'y_bin'], as_index=False)[lf].mean()[lf]
iNat_melt = pd.melt(grouped_all, id_vars=['x_bin','y_bin'], 
        value_vars=["cover_tree","cover_shrub","cover_herb"],
        value_name= "iNat coverage")
sPlot_melt = pd.melt(sPlot_raster, id_vars=['x_bin','y_bin'], 
        value_vars=["cover_tree","cover_shrub","cover_herb"],
        value_name= "sPlot coverage")
raster = pd.merge(iNat_melt, sPlot_melt, on=['x_bin','y_bin', 'variable'])
g = sns.relplot(
    data=raster,
    x="sPlot coverage", y="iNat coverage",
    col="variable", 
    kind="scatter", 
    col_wrap=4, 
    linewidth=0,
    alpha=0.5,
    color="midnightblue",
    palette='crest',
    facet_kws={'sharey': False, 'sharex': False}
)

for traits, ax in g.axes_dict.items():

    ax.axline([0, 0], [1, 1], color= "black", alpha=0.4)
_images/Chapter_11_Growth_Forms_Coverage_41_0.png

Over biomes#

iNat_with_biome = pd.read_csv("iNat_biomes.csv")
iNat_with_biome.head()
gbifID scientificName decimalLatitude decimalLongitude eventDate dateIdentified Dispersal unit length Leaf Area SLA Leaf C ... Leaf N P ratio Leaf P Plant Height Seed mass Seed length Seeds per rep. unit Stem conduit density SSD Conduit element length BIOME
0 1990599612 Macaranga tanarius 23.122994 120.534961 2019-01-25T14:51:00 2019-01-27T13:49:07 NaN 10.997687 2.848944 NaN ... NaN 1.064711 2.183426 3.427650 NaN NaN NaN -0.785087 NaN 1.0
1 1990599668 Adiantum capillus-veneris 23.123053 120.536422 2019-01-25T15:36:00 2019-01-27T14:22:54 NaN 4.088585 4.030621 NaN ... NaN -1.021651 -1.213114 -1.890699 NaN NaN NaN NaN NaN 1.0
2 1978441599 Chloris barbata 23.123362 120.183891 2018-12-16T17:21:58 2018-12-16T13:14:40 NaN NaN NaN NaN ... NaN NaN NaN -1.565953 NaN NaN NaN NaN NaN 1.0
3 1883470731 Adiantum capillus-veneris 23.123363 120.536638 2018-03-11T11:48:00 2018-07-07T12:43:18 NaN 4.088585 4.030621 NaN ... NaN -1.021651 -1.213114 -1.890699 NaN NaN NaN NaN NaN 1.0
4 2242806671 Dioscorea bulbifera 23.123399 120.533835 2019-04-28T10:44:00 2019-05-03T12:45:18 NaN 5.093750 3.785888 NaN ... NaN NaN NaN 1.736951 NaN NaN NaN NaN NaN 1.0

5 rows × 25 columns

biomes = list(iNat_with_biome['BIOME'].unique())

for b in biomes:

    sub_iNat_with_biome = iNat_with_biome[iNat_with_biome["BIOME"]==b]

    iNat_lf = pd.merge(sub_iNat_with_biome, growth_forms_sum, on='scientificName', how='inner')
    iNat_lf['life form'] = iNat_lf[["is_tree", "is_shrub", "is_herb"]].idxmax(axis="columns")
    iNat_lf = iNat_lf[iNat_lf["life form"].notna()]

    plt.rcParams.update({'font.size': 15})

    step = 181

    bins_x = np.linspace(-180,180,step) 
    bins_y= np.linspace(-90,90,int(((step - 1)/2)+1))
    iNat_lf['x_bin'] = pd.cut(iNat_lf['decimalLongitude'], bins=bins_x)
    iNat_lf['y_bin'] = pd.cut(iNat_lf['decimalLatitude'], bins=bins_y)
    iNat_lf['x_bin'] = iNat_lf['x_bin'].apply(lambda x: x.left)
    iNat_lf['y_bin'] = iNat_lf['y_bin'].apply(lambda x: x.left)

    iNat_tree = iNat_lf[iNat_lf['life form']== "is_tree"]
    iNat_shrub = iNat_lf[iNat_lf['life form']== "is_shrub"]
    iNat_herb = iNat_lf[iNat_lf['life form']== "is_herb"]

    grouped_all = iNat_lf.groupby(['x_bin', 'y_bin'], as_index=False)['life form'].size()

    grouped_trees = iNat_tree.groupby(['x_bin', 'y_bin'], as_index=False)['life form'].size()
    grouped_shrubs = iNat_shrub.groupby(['x_bin', 'y_bin'], as_index=False)['life form'].size()
    grouped_herbs = iNat_herb.groupby(['x_bin', 'y_bin'], as_index=False)['life form'].size()

    grouped_all['cover_tree'] = grouped_trees['size']/grouped_all['size']
    grouped_all['cover_shrub'] = grouped_shrubs['size']/grouped_all['size']
    grouped_all['cover_herb'] = grouped_herbs['size']/grouped_all['size']
    
    # print correlation

    print(b)

    for lf in ['cover_tree', 'cover_shrub', 'cover_herb']:
        sPlot_raster[lf] = sPlot_cover.groupby(['x_bin', 'y_bin'], as_index=False)[lf].mean()[lf]        
        correlation_xy = sPlot_raster[lf].corr(grouped_all[lf])
        print(lf + " " + str(correlation_xy**2))
    
    iNat_melt = pd.melt(grouped_all, id_vars=['x_bin','y_bin'], 
        value_vars=["cover_tree","cover_shrub","cover_herb"],
        value_name= "iNat cover")
    sPlot_melt = pd.melt(sPlot_raster, id_vars=['x_bin','y_bin'], 
        value_vars=["cover_tree","cover_shrub","cover_herb"],
        value_name= "sPlot cover")
    
    raster = pd.merge(iNat_melt, sPlot_melt, on=['x_bin','y_bin', 'variable'])
    
    g = sns.relplot(
    data=raster,
    x="sPlot cover", y="iNat cover",
    col="variable", 
    #hue="NumberiNatObservations", 
    #size="NumberiNatObservations",
    kind="scatter", 
    #hue="Weights",
    col_wrap=4, 
    #aspect = 1,  height = 4,
    linewidth=0,
    alpha=0.5,
    color="midnightblue",
    palette='crest',
    facet_kws={'sharey': False, 'sharex': False})
    
    index=0
    for traits, ax in g.axes_dict.items():
        ax.axline([0, 0], [1, 1], color= "black", alpha=0.4)
        # Iterate over each subplot to customize further

        trait_title= b
        # Add the title as an annotation within the plot
        ax.text(.1, .95, trait_title, transform=ax.transAxes, fontweight="bold")
        index+=1
        ax.axline([0, 0], [1, 1], color= "black", alpha=0.4)


    
    filename = '../Figures/corr_biome' + str(b) + '_cover.pdf'
    plt.savefig(filename, bbox_inches='tight')  
1.0
cover_tree 0.01943613258365132
cover_shrub 0.028058360539673456
cover_herb 0.0022278128815516945
2.0
cover_tree 0.00495158098325045
cover_shrub 0.0021841156153433973
cover_herb 0.0017625094597744017
3.0
cover_tree 0.27454095391406436
cover_shrub 0.02880357026669633
cover_herb 0.004831038955014629
4.0
cover_tree 0.259079820611657
cover_shrub 0.006749994097072907
cover_herb 0.23471860018958288
5.0
cover_tree 0.0902670010518872
cover_shrub 0.07357112645012613
cover_herb 0.17702590884327152
6.0
cover_tree 0.015465784550899028
cover_shrub 0.014347538706417832
cover_herb 0.010721767313240553
7.0
cover_tree 0.003077455550975538
cover_shrub 2.643230909102668e-05
cover_herb 0.018979266464673905
8.0
cover_tree 0.019313094032917352
cover_shrub 0.1095073129145167
cover_herb 0.13137953769498106
9.0
cover_tree 1.9096182179645747e-05
cover_shrub 0.16424750138680017
cover_herb 0.12904371358220107
10.0
cover_tree 0.015454822638076557
cover_shrub 0.00029106358542621644
cover_herb 0.04854474044738274
11.0
cover_tree 0.02413902443214224
cover_shrub 0.023572234963179787
cover_herb 0.04896684519451854
12.0
cover_tree 0.06588072711803293
cover_shrub 0.01176192277333619
cover_herb 0.014151478930656908
13.0
cover_tree 0.07586388909129714
cover_shrub 0.036485178451133755
cover_herb 0.03687038140378628
14.0
cover_tree 0.08233330012387073
cover_shrub 0.00024794574677113615
cover_herb 0.0372847032193021
_images/Chapter_11_Growth_Forms_Coverage_45_1.png _images/Chapter_11_Growth_Forms_Coverage_45_2.png _images/Chapter_11_Growth_Forms_Coverage_45_3.png _images/Chapter_11_Growth_Forms_Coverage_45_4.png _images/Chapter_11_Growth_Forms_Coverage_45_5.png _images/Chapter_11_Growth_Forms_Coverage_45_6.png _images/Chapter_11_Growth_Forms_Coverage_45_7.png _images/Chapter_11_Growth_Forms_Coverage_45_8.png _images/Chapter_11_Growth_Forms_Coverage_45_9.png _images/Chapter_11_Growth_Forms_Coverage_45_10.png _images/Chapter_11_Growth_Forms_Coverage_45_11.png _images/Chapter_11_Growth_Forms_Coverage_45_12.png _images/Chapter_11_Growth_Forms_Coverage_45_13.png _images/Chapter_11_Growth_Forms_Coverage_45_14.png