Manhattan’s Urban Forestry Report, 2015

Manhattan’s Urban Forestry Report, 2015

Tableau Public

Introduction

The urban design team believes that tree size (in terms of trunk diameter) and health are the most desirable characteristics of city trees. In order to help the planning department improve the quantity and quality of trees in New York City, our organization is advised to provide a data analysis report.

Objectives

The main objective of this report is to profile Manhattan’s tree population and species by different attributes using summary statistics, visualizations, and textual explanations. Specifically, it aims to: | |
|:—————|
| ㅤ 1. Describe all censused trees by their spatial and biological characteristics.| | ㅤ 2. Map the tree profile of the neighborhoods. | |ㅤ 3. Illustrate the biodiversity and biology of the tree species in Manhattan. | |ㅤ 4. Determine tree species with the best traits. | | |

Data Used

The following data sets come from the City of New York NYC Open Data.

Trees

A data set based on the “TreesCount! $2015$ Street Tree Census, conducted by volunteers and staff organized by NYC Parks & Recreation and partner organizations. Tree data collected includes tree species, diameter and perception of health. Accompanying blockface data is available indicating status of data collection and data release citywide”.

See the list of variables and their descriptions here.

Neighborhoods

A data set based on the “boundaries of Neighborhood Tabulation Areas as created by the NYC Department of City Planning using whole census tracts from the $2010$ Census as building blocks. These aggregations of census tracts are subsets of New York City’s $55$ Public Use Microdata Areas (PUMAs).”

See the list of variables and their descriptions here.

Executive Summary

Using the data available and findings of the analyses, the tree population and species of Manhattan, New York City, can be summarized as follows:

  • Greater numbers of trees are most likely to be found in neighborhoods with larger plots of land.
  • The majority of the trees in Manhattan are on-curb, with only a few that are offset from the curb.
  • The majority of the trees in Manhattan are alive and in fair to good health, while only a small number are dead and in poor health.
  • Although specific root, trunk, and branch problems are not of significant concerns, few of the trees are affected by paving stones in the tree bed (a kind of root problem) as well as other unspecified trunk and branch problems.
  • Manhattan has a rich and diverse set of tree species.
  • The species recommendation for tree planting in Manhattan’s streets is a combination of some of the borough’s highly and averagely abundant species that have shown favorable qualities of size and health. Specifically, the top five recommended species are as follows:

    1. Siberian elm

    2. Willow oak

    3. Honeylocust

    4. American elm

    5. Pin oak

Results & Discussion

Tree Population

Using descriptive and spatial analyses, the following information outlines the location and physical attributes of all Manhattan trees in $2015$ with a population size ($N$) of $64,229$:

Spatial

Tree Locations by Neighborhood:

While trees seem to cover much each of Manhattan’s $28$ neighborhoods, some of the southern ones, including MN13, MN17, MN24, MN25, MN27, MN28, and MN50, have empty areas. Interestingly, four of these aforementioned neighborhoods (indicated by *) are among the top ten in terms of land size, which are:

  1. *Hudson Yards-Chelsea-Flatiron-Union Square (MN13)
  2. Upper West Side (MN12)
  3. *Midtown-Midtown South (MN17)
  4. Central Harlem North-Polo Grounds (MN03)
  5. West Village (MN23)
  6. *SoHo-TriBeCa-Civic Center-Little Italy (MN24)
  7. East Harlem North (MN34)
  8. *Lower East Side (MN28)
  9. Washington Heights South (MN36)
  10. Washington Heights North (MN35)

</ol>

# ---------- Packages & Datasets

# Load pre-installed, required packages
suppressPackageStartupMessages(library(tidyverse)) 
suppressPackageStartupMessages(library(dplyr)) 
suppressPackageStartupMessages(library(ggplot2))
suppressPackageStartupMessages(library(sf))
suppressPackageStartupMessages(library(geojsonsf))
suppressPackageStartupMessages(library(scales))

# Install & load the 'rwantshue' package for generating random color scheme
suppressWarnings(suppressMessages(install.packages("remotes", quiet=TRUE)))
suppressWarnings(suppressMessages(remotes::install_github("hoesler/rwantshue", auth_token="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", quiet=TRUE)))
suppressPackageStartupMessages(library(rwantshue))

# Install & load the 'ggfun' package for round rectangle borders and backgrounds in ggplots
suppressWarnings(suppressMessages(install.packages("ggfun", quiet=TRUE)))
suppressPackageStartupMessages(library(ggfun))

# Install & load the 'ggchicklet' package for bar charts with rounded corners
suppressWarnings(suppressMessages(remotes::install_github("hrbrmstr/ggchicklet", auth_token="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", quiet=TRUE)))
suppressPackageStartupMessages(library(ggchicklet))

# Read the 'trees' data set from the CSV file
trees <- readr::read_csv("data/trees.csv", show_col_types=FALSE) %>%
	mutate(spc_common = str_to_sentence(spc_common))

# Read the 'neighborhoods' data set from the SHP file
neighborhoods <- st_read("data/nta.shp", quiet=TRUE) %>% 
	dplyr::select(boroname, ntacode, ntaname, geometry, shape_area)

# Create a merged data frame for the 'trees' and 'neighborhoods' data sets
merged_trees_and_neighborhoods <- trees %>%
	full_join(neighborhoods, by = c("nta"="ntacode", "nta_name"="ntaname"))
defaultW <- getOption("warn")
options(warn=-1)

# ---------- Results & Discussion

# ----- Tree Population

# -- Spatial

# Top 10 NTAs in terms of land size 
top_nta_area <- neighborhoods %>%
  filter(boroname == "Manhattan", ntacode != "MN99") %>%
  arrange(desc(shape_area)) %>%
  slice(1:10)

# Tree count per neighborhood
nbh_tree_cnts <- merged_trees_and_neighborhoods %>%
  filter(boroname == "Manhattan", nta != "MN99") %>%
  group_by(nta, nta_name) %>%
  summarize(number_of_trees = n(), .groups="keep") %>%
  arrange(desc(number_of_trees)) %>%
  ungroup() %>%
  mutate(proportion = round(number_of_trees/sum(number_of_trees), digits = 4))

# Species richness per neighborhood
nbh_rchns <- trees %>%
  filter(!(spc_common=="null")) %>%
  group_by(nta, nta_name) %>%
  summarize(richness = n_distinct(spc_common), .groups="keep") %>%
  arrange(desc(richness)) %>%
  ungroup()

# Data for maps
nbhs_map <- nbh_tree_cnts %>%
  full_join(neighborhoods, c("nta"="ntacode", "nta_name"="ntaname")) %>% 
  full_join(nbh_rchns, c("nta", "nta_name")) %>%
  mutate(borough = substr(nta, 1, 2),
         nta_code_and_name = paste(nta, nta_name, sep=": "),
         nta_and_tree_cnt = ifelse(number_of_trees < 1000, 
                                   paste(nta,  " - ", "   ", prettyNum(number_of_trees,big.mark=","), " : ", nta_name, sep=""),
                                   paste(nta,  " - ", prettyNum(number_of_trees, big.mark=","), " : ", nta_name, sep="")
         ),
         nta_and_rchns = paste(nta,  " - ", prettyNum(richness, big.mark=","),
                               " : ", nta_name, sep="")
  ) %>%
  st_as_sf %>%
  st_transform("+proj=longlat +ellps=intl +no_defs +type=crs") 

# Colorize the NTAs
color_scheme <- iwanthue(seed=1234, force_init=TRUE)
nta_colors <- color_scheme$hex(nrow(nbhs_map %>%  filter(borough == "MN")))

# Data of tree locations 
tree_locs <- trees %>%
  st_as_sf(coords = c("longitude", "latitude"), crs=4326) %>%
  st_transform("+proj=longlat +ellps=intl +no_defs +type=crs")


# Map of tree locations by neighborhood
tree_locs_map_plot <- ggplot() + 
  geom_sf(data = nbhs_map,
          fill="#E8EAED", color="grey") +
  stat_sf_coordinates(data = tree_locs, 
                      aes(color = paste(nta, nta_name, sep=": ")),
                      size=0.001
  ) +
  stat_sf_coordinates(data = nbhs_map %>% filter(borough=="MN", nta!="MN99"),
                      color="grey25", size=0.25) +
  geom_sf(data = nbhs_map %>% filter(borough=="MN", nta!="MN99"),
          color="grey25",
          alpha=0.1) + 
  theme(legend.position = c(0.024, 0.5),
        legend.justification=0.0,
        legend.key.width = unit(2.5, 'mm'),
        legend.key.height = unit(1.8, 'mm'), 
        legend.direction="vertical",
        legend.background= element_roundrect(r = grid::unit(0.02, "snpc"),
                                             fill=alpha("#FFFFFF", 0.90)),
        legend.key = element_rect(fill=NA),
        legend.text = element_text(margin = margin(r=5, unit="pt"),
                                   color="#65707C",
                                   family="sans serif"),
        legend.title = element_text(face="bold",
                                    color="#65707C",
                                    size=8.5,
                                    family="sans serif"),
        axis.title = element_text(color="#65707C",
                                  face="bold",
                                  family="sans serif"),
        axis.text = element_text(color="#65707C",
                                 size=7,
                                 family="sans serif"),
        axis.text.x = element_text(angle=90,
                                   vjust=0.5,
                                   hjust=1),
        axis.line = element_line(colour="grey",
                                 linewidth=0.5),
        panel.grid.major = element_line(color="grey",
                                        linetype="dashed",
                                        linewidth=0.25),
        panel.border = element_rect(color="grey40",
                                    fill=NA),  
        panel.spacing = unit(2, "lines"),
        panel.background  = element_roundrect(r = grid::unit(0.001, "snpc"),
                                              fill=alpha("#9CC0F9", 1)),
		rect = element_rect(fill = "transparent"),
        plot.title = element_text(color="#65707C",
                                  vjust=10,
                                  size=14,
                                  family="sans serif")) +
  labs(x="", y="", color="    Code: Name") +
  ggtitle("Fig. 1: Map of the Tree Locations by Neighborhood in Manhattan") +
  scale_x_continuous(limits = c(-74.25, -73.89), 
                     breaks = seq(-74.25, -73.89, by=0.02)) +
  scale_y_continuous(limits = c(40.68, 40.88), 
                     breaks = seq(40.68, 40.88, by=0.02)) +
  guides(color = guide_legend(ncol=1,
                              override.aes = list(shape=15,
                                                  size=2.5
                              ))) +
  ggrepel::geom_text_repel(data = nbhs_map %>% filter(borough == "MN", nta != "MN99"),
                            aes(label = nta, geometry = geometry),
                            stat="sf_coordinates",
                            min.segment.length=0,
                            size=2,
                            label.size=NA,
						    fontface="bold"
						  ) +
  coord_sf(xlim = c(-74.25, -73.89), ylim = c(40.68, 40.88)) +
  scale_color_manual(values = nta_colors)

options(warn = defaultW)
# ----- For link's image thumbnail

# Install and load the 'patchwork' package
suppressWarnings(suppressMessages(install.packages("patchwork", quiet=TRUE))) 
suppressPackageStartupMessages(library(patchwork))

# Install and load the 'png' package
suppressWarnings(suppressMessages(install.packages("png", quiet=TRUE)))       
suppressPackageStartupMessages(library(png))

# Create a data
data <- data.frame(x = 1:3,
                   y = 1:3)

# Read the PNG file
my_image <- readPNG("cover.png", native = TRUE)

# Create a plot and combine with the image
cover_img <- ggplot(data, aes(x, y)) +
	geom_point() +
	theme_minimal() +
	theme(axis.title = element_blank(),
          axis.text = element_blank(),
          axis.line = element_blank(),
          axis.ticks = element_blank()) +
	inset_element(p = my_image,
                  left=-0.1,
                  bottom=-0.5,
                  right=1.23,
                  top=1.5)
cover_img

png

# Export plot as PNG
ggsave(
	plot = tree_locs_map_plot + theme(plot.title = element_text(hjust=1.25)),
	filename = "documentation/tree_locs_map_plot.png",
	bg = "transparent"
)
Saving 7 x 7 in image
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”

Tree Counts by Neighborhood:

In terms of the number of trees, the top ten neighborhoods are:

  1. *Upper West Side (MN12)
  2. Upper East Side-Carnegie Hill (MN40)
  3. *West Village (MN23)
  4. *Central Harlem North-Polo Grounds (MN03)
  5. *Hudson Yards-Chelsea-Flatiron-Union Square (MN13)
  6. *Washington Heights South (MN36)
  7. Morningside Heights (MN09)
  8. Central Harlem South (MN11)
  9. *Washington Heights North (MN35)
  10. *East Harlem North (MN34)

Seven of which (indicated by *) are part of the ten largest.

defaultW <- getOption("warn")
options(warn=-1)

# neighborhoods %>% 
# 	st_set_geometry(NULL) %>%
# 	summarize(total_number_of_neighborhoods_in_the_data_set = n())

# neighborhoods %>% 
# 	st_set_geometry(NULL) %>% 
# 	filter(str_detect(ntacode, "MN")) %>%
# 	summarize(number_of_neighborhoods_from_manhattan_in_the_data_set = n())

# merged_trees_and_neighborhoods %>% 
# 	group_by(nta) %>% 
# 	summarize(number_of_trees_per_neighborhood = n()) %>%
# 	summarize(number_of_neighborhoods_from_manhattan_with_trees = n())

# neighborhoods %>%
# 	st_set_geometry(NULL) %>%
# 	anti_join(trees, by = c("ntacode" = "nta", "ntaname" = "nta_name")) %>% 
# 	filter(str_detect(ntacode, "MN"))


# Table for Top 10 Tree-Producing Neighborhoods
for_table_nbh_tree_cnts <- nbh_tree_cnts %>%
	slice(1:10) %>%
	rownames_to_column("rank") %>%
	mutate(number_of_trees = prettyNum(number_of_trees, big.mark=","),
           percentage = label_percent(accuracy=0.01)(proportion)) %>%
	select(-proportion)

# HTML Table for Top 10 Most Abundant Species
#kable(for_table_nbh_tree_cnts, 
#      caption = " ",
#      label = "tables", format = "html", booktabs = TRUE)

# Order by number of trees
nbhs_map$nta_and_tree_cnt <- factor(
    nbhs_map$nta_and_tree_cnt,
       levels = nbhs_map$nta_and_tree_cnt,
       ordered=TRUE
)

# Map of NTAs' tree counts
nbhs_tree_cnts_map_plot <- ggplot() + 
	geom_sf(data = nbhs_map %>% filter(borough != "MN" | nta == "MN99"),
            fill="#E8EAED", color="grey") +
	geom_sf(data = nbhs_map %>% filter(borough == "MN", nta != "MN99"),
            aes(fill = number_of_trees,
                color = nta_and_tree_cnt
           )) + 
    stat_sf_coordinates(data = nbhs_map %>% filter(nta %in% for_table_nbh_tree_cnts$nta),
                        color="grey25", size=0.5) +
    theme(legend.position = #c(0.7, 0.8),
          c(0.369, 0.5), 
          #c(0.025, 0.5),
          legend.justification=0.0,
          legend.key.width = unit(2.5, 'mm'),
	      legend.key.height = unit(1.8, 'mm'), 
          legend.direction="vertical",
          legend.background = element_roundrect(r = grid::unit(0.02, "snpc"),
                                               fill = alpha("#FFFFFF", 0.90)),
          legend.key = element_rect(fill=NA),
          legend.text = element_text(margin = margin(r=5, unit="pt"),
                                     size=7.9,
        	                         color="#65707C",
                                     family="sans serif"),
          legend.title = element_text(face="bold",
                                      color="#65707C",
                                      size=8.5,
                                      family="sans serif"),
          axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color="#65707C",
                                   size=7,
                                   family="sans serif"),
          axis.text.x = element_text(angle=90,
                                     vjust=0.5,
                                     hjust=1),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.border = element_rect(color="grey40",
                                      fill=NA),  
          panel.spacing = unit(2, "lines"),
          panel.background  = element_roundrect(r = grid::unit(0.001, "snpc"),
                                               fill = alpha("#9CC0F9", 1)),
		  rect = element_rect(fill = "transparent"),
          plot.title = element_text(color="#65707C",
                                    vjust=10,
                                    size=14,
                                    family="sans serif")) +
		 labs(x="", y="", color="   Code - Number of trees : Name"
             ) +
		 ggtitle("Fig. 2: Map of the Number of Trees in Manhattan's Neighborhoods") +
	scale_x_continuous(expand = c(0.01, 0),
                       limits = c(-74.04, -73.64), 
                       breaks = seq(-74.04, -73.64, by=0.02)) +
	scale_y_continuous(expand = c(0.01, 0),
                       limits = c(40.68, 40.88), 
                       breaks = seq(40.68, 40.88, by=0.02)) +
	scale_color_manual(values = replicate(28, "grey25")) +
	scale_fill_gradient2(low = muted("499F78"),
                         high = muted("#216968")) +
	ggrepel::geom_text_repel(data = nbhs_map %>% filter(nta %in% for_table_nbh_tree_cnts$nta),
                              aes(label = nta, geometry = geometry),
                              stat="sf_coordinates",
                              min.segment.length=0,
                              label.size=NA,
                              alpha=0.5,
						      fontface="bold"
							 ) +
	coord_sf(xlim = c(-74.04, -73.64), ylim = c(40.68, 40.88))     #-74.28, -73.88

# Extract NTA fill colors
color_scheme_2 <- as.data.frame(ggplot_build(nbhs_tree_cnts_map_plot)$data[[2]])$fill

nbhs_tree_cnts_map_plot1 <- nbhs_tree_cnts_map_plot +
	guides(fill = "none",
           color = guide_legend(ncol=1,
                                override.aes = list(color = NA,
                                                    fill = color_scheme_2,
                                                    linewidth=0))
          )

#nbh_tree_cnts %>%
#	#slice(1:10) %>%
#	#rownames_to_column("rank") %>%
#	mutate(number_of_trees = prettyNum(number_of_trees, big.mark=","),
#           percentage = label_percent(accuracy=0.01)(proportion)) %>%
#	select(-proportion)

options(warn = defaultW)
nbh_tree_cnts %>%
	slice(1:10) %>%
	rownames_to_column("rank") %>%
	mutate(number_of_trees = prettyNum(number_of_trees, big.mark=","),
          percentage = label_percent(accuracy=0.01)(proportion)) %>%
	select(-proportion)
A tibble: 10 × 5
rankntanta_namenumber_of_treespercentage
<chr><chr><chr><chr><chr>
1MN12Upper West Side5,8079.04%
2MN40Upper East Side-Carnegie Hill4,6167.19%
3MN23West Village3,8015.92%
4MN03Central Harlem North-Polo Grounds3,4695.40%
5MN13Hudson Yards-Chelsea-Flatiron-Union Square2,9314.56%
6MN36Washington Heights South2,9244.55%
7MN09Morningside Heights2,7044.21%
8MN11Central Harlem South2,6434.11%
9MN35Washington Heights North2,6124.07%
10MN34East Harlem North2,5053.90%
# Export plot as PNG
ggsave(
	plot = nbhs_tree_cnts_map_plot1 + theme(plot.title = element_text(hjust=1.1)),
	filename = "documentation/nbhs_tree_cnts_map_plot.png",
	bg = "transparent"
)
Saving 7 x 7 in image
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”
Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
“st_point_on_surface may not give correct results for longitude/latitude data”

Trees by Curb Location:

Majority or $93.31\%$ ($59,932$) of the tree beds are located on curb, while the remaining $6.69\%$ $(4,297)$ are located offset from curb.

# Tree count per location in relation to curb
number_of_trees_per_curb_loc <- merged_trees_and_neighborhoods %>%
	filter(str_detect(nta, "MN") & !(nta == "MN99")) %>%
	group_by(curb_loc) %>%
	summarize(number_of_trees = n()) %>%
	arrange(desc(number_of_trees)) %>%
    mutate(percentage = label_percent(accuracy=0.01)(number_of_trees/length(merged_trees_and_neighborhoods$tree_id)))

# HTML Table for Curb Location
#kable(number_of_trees_per_curb_loc,
#      caption = "This is the caption.",
#      label = "tables", format = "html", booktabs = TRUE) 

on_curb_stat <- number_of_trees_per_curb_loc %>%
    mutate(proportion = number_of_trees/sum(number_of_trees)) %>% 
	filter(proportion == max(abs(proportion)))

# Create a pie chart for the curb location
curb_loc_stacked_bar_plot <- ggplot(number_of_trees_per_curb_loc) + 
	geom_chicklet(aes(x="", y = number_of_trees/sum(number_of_trees),
                      fill = curb_loc), 
                  radius = grid::unit(0.75, "mm"),
                  position="stack") +
	coord_flip() +
	theme(legend.position="right",
          legend.justification="top",
          legend.direction="vertical",
          legend.key.size = unit(0, 'pt'),
          #legend.key = element_rect(fill = NA),
          legend.text = element_text(margin = margin(r = 4, unit = "pt"),
                                     color = "#65707C",
                                     family="sans serif"),
          legend.title = element_text(color = "#65707C",
                                      face="bold",
                                      size = 9,
                                      family="sans serif"),
		  axis.title.x = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
		  axis.title.y = element_blank(),
          axis.text = element_blank(),
          axis.line = element_blank(),
          axis.ticks = element_blank(),
          panel.grid.minor = element_blank(),
          panel.grid.major = element_blank(),
          panel.background = element_blank(),
		  rect = element_rect(fill = "transparent"),
          plot.subtitle = element_text(color="#65707C",
                                    hjust=0.25,
                                    size=10,
                                    family="sans serif"),
          plot.title = element_text(color="#65707C",
                                    hjust=-0.15,
                                    size=14,
                                    family="sans serif"),
		  plot.margin = unit(c(0,1,0,1), "cm")) +	
	scale_fill_manual(values = c("#875826",
                                 "#10401B")) + 
	ggtitle("\nFig. 3: Proportional Stacked Bar Graph of Tree Bed Location ",
            subtitle="  (in relation to the Curb)\n") +
	labs(y="\n%  \n(Number of trees)\n", fill="Location:  ") +
    guides(fill = guide_legend(nrow=2,
                               reverse=TRUE,
                               override.aes = list(shape = 15,
                                                   size = 4))) +
	scale_x_discrete(expand = c(0.01, 0)) +
	geom_text(data = on_curb_stat,
                             aes(label = paste(label_percent(accuracy=0.01)(proportion),
                                       "\n (", prettyNum(number_of_trees,
                                                  big.mark=","),")",
                                       sep=""),
                                 x = "",
                                 y = 0.50 * proportion - 0.075),
                            size=5, color="white", hjust=1)
# Export plot as PNG
ggsave(
	plot = curb_loc_stacked_bar_plot,
	filename = "documentation/curb_loc_stacked_bar_plot.png",
	bg = "transparent"
)
Saving 7 x 7 in image

Trees’ Curb Location by Neigborhood:

Twenty neighborhoods have at least $90\%$ of their trees being on curb, while $27$ have at least $75\%$. The ten neighborhoods with the highest percentage of trees located on-curb are:

  1. East Village (MN22)
  2. Manhattanville (MN06)
  3. Gramercy (MN21)
  4. West Village (MN23)
  5. Hudson Yards-Chelsea-Flatiron-Union Square (MN13)
  6. Yorkville (MN32)
  7. Clinton (MN15)
  8. Washington Heights North (MN35)
  9. Lenox Hill-Roosevelt Island (MN31)
  10. East Harlem North (MN34)

Only Stuyvesant Town-Cooper Village has the majority of its trees being offset from curb. Including it, the neighborhoods with the highest percentage of trees located offset from curb are:

  1. Stuyvesant Town-Cooper Village (MN50)
  2. Battery Park City-Lower Manhattan (MN25)
  3. Chinatown (MN27)
  4. Morningside Heights (MN09)
  5. East Harlem South (MN33)
  6. Lower East Side (MN28)
  7. SoHo-TriBeCa-Civic Center-Little Italy (MN24)
  8. Upper West Side (MN12)
  9. Lincoln Square (MN14)
  10. Upper East Side-Carnegie Hill (MN40)
#########################################
#### Characteristics by Neighborhood ####
#########################################

## Location ##

# Location in relation with the curb 
nta_curb_loc <- as.data.frame.matrix(table(trees$nta, trees$curb_loc)) %>%
	rename_with( ~ paste0(.x, "_loc"))

## Biology ##

# Species
nta_spc <- as.data.frame.matrix(table(trees$nta, trees$spc_common))

# Tree size (in terms of trunk diameter)
nta_tree_dbh <- as.data.frame.matrix(table(trees$nta, trees$tree_dbh)) %>%
	rename_with( ~ paste0(.x, "_tree_dbh"))

# Status and health 
nta_status <- as.data.frame.matrix(table(trees$nta, trees$status)) %>%
	rename_with( ~ paste0(.x, "_status"))
nta_health <- as.data.frame.matrix(table(trees$nta, trees$health)) %>%
	rename_with( ~ paste0(.x, "_health"))

# Root problems
nta_root_stone <- as.data.frame.matrix(table(trees$nta, trees$root_stone)) %>%
	rename_with( ~ paste0(.x, "_root_stone"))
nta_root_grate <- as.data.frame.matrix(table(trees$nta, trees$root_grate)) %>%
	rename_with( ~ paste0(.x, "_root_grate"))
nta_root_other <- as.data.frame.matrix(table(trees$nta, trees$root_other)) %>%
	rename_with( ~ paste0(.x, "_root_other"))

# Trunk problems
nta_trunk_wire <- as.data.frame.matrix(table(trees$nta, trees$trunk_wire)) %>%
	rename_with( ~ paste0(.x, "_trunk_wire"))
nta_trnk_light <- as.data.frame.matrix(table(trees$nta, trees$trnk_light)) %>%
	rename_with( ~ paste0(.x, "_trnk_light"))
nta_trnk_other <- as.data.frame.matrix(table(trees$nta, trees$trnk_other)) %>%
	rename_with( ~ paste0(.x, "_trnk_other"))

# Branch problems
nta_brch_light <- as.data.frame.matrix(table(trees$nta, trees$brch_light)) %>%
	rename_with( ~ paste0(.x, "_brch_light"))
nta_brch_shoe <- as.data.frame.matrix(table(trees$nta, trees$brch_shoe)) %>%
	rename_with( ~ paste0(.x, "_brch_shoe"))
nta_brch_other <- as.data.frame.matrix(table(trees$nta, trees$brch_other)) %>%
	rename_with( ~ paste0(.x, "_brch_other"))

# Table of biological attributes per species
nta_bio <- bind_cols(list(nta_tree_dbh,
                          nta_status,
                          nta_health,
                          nta_root_stone,
                          nta_root_grate,
                          nta_root_other,
                          nta_trunk_wire,
                          nta_trnk_light,
                          nta_trnk_other,
                          nta_brch_light,
                          nta_brch_shoe,
                          nta_brch_other)) %>%
	rownames_to_column("nta")
# Curb location per neighborhood
curb_loc_per_nbh <- merged_trees_and_neighborhoods %>% 
	filter(str_detect(nta, "MN") & !(nta == "MN99")) %>%
	group_by(nta, nta_name, curb_loc) %>%
	summarize(number_of_trees=n(), .groups="keep") %>%
	group_by(nta) %>%
	mutate(proportion = number_of_trees/sum(number_of_trees),
           percentage = label_percent(accuracy=0.01)(proportion)) %>%
	arrange(desc(proportion)) %>%
	ungroup()

# Higher between OnCurb and OffsetFromCurb per neighborhood
oncurb_vs_offset_per_nbh <- curb_loc_per_nbh %>% 
	group_by(nta) %>%
	filter(proportion == max(abs(proportion)))

# Order by NTA
curb_loc_per_nbh$nta_name <- factor(
    curb_loc_per_nbh$nta_name,
       levels = rev(unique(curb_loc_per_nbh$nta_name)),
       ordered=TRUE
)

# Table of Top 10 NTAs with the highest % of on-curb-located trees
top_on_curb <- curb_loc_per_nbh %>%
	filter(curb_loc=="OnCurb") %>%
	top_n(10, proportion) %>%
	arrange(desc(proportion)) %>%
    rownames_to_column("rank") %>%
	rename(number_of_on_curb_trees = number_of_trees)

# HTML Table of Top 10 NTAs with the highest % of on-curb-located trees
#kable(top_on_curb %>% 
#      	 select(rank, nta, nta_name, number_of_on_curb_trees, percentage),
#      caption = " ",
#      label = "tables", format = "html", booktabs = TRUE) 

curb_loc_per_nbh_stacked_bar_plot <- ggplot(curb_loc_per_nbh) + 
	geom_chicklet(aes(x = nta_name, y = proportion*100, fill = curb_loc), 
                  radius = grid::unit(0.75, "mm"), position="stack") +
	coord_flip() +
	theme(legend.position="right",
          legend.justification="top",
          legend.direction="vertical",
          legend.key.size = unit(0, "pt"),
          legend.key = element_rect(fill=NA),
          legend.text = element_text(margin = margin(r = 4, unit = "pt"),
                                     color="#65707C",
                                     family="sans serif"),
          legend.title = element_text(color="#65707C",
                                      face="bold",
                                      size=9,
                                      family="sans serif"),
		  axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text.x = element_text(color="#65707C",
                                   size=6,
                                   family="sans serif"),
          axis.text.y = element_text(color="#65707C",
                                   size=10,
                                   family="sans serif"),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.subtitle = element_text(color="#65707C",
                                    hjust=5.38,
                                    size=10,
                                    family="sans serif"),
          plot.title = element_text(color = "#65707C",
                                    hjust = 0.709,
                                    size= 12.2,
                                    family = "sans serif")) +
	scale_fill_manual(values = c("#875826",
                                 "#10401B")) +     
	ggtitle("\nFig. 4: Proportional Stacked Bar Graph of Each Neighborhood's Tree Bed Location",
            subtitle="               (in relation to the Curb)\n") +
	labs(x="\nNTA name \n", y="\nNTA code - % of on trees\n", fill="Location: ") +
    guides(fill = guide_legend(ncol=1,
                               reverse=TRUE,
                               override.aes = list(shape = 15,
                                                   size = 4))) +
	scale_y_continuous(expand = c(0.01, 0),
                       breaks = seq(0, 100, by=10)) +
	ggrepel::geom_text_repel(data = oncurb_vs_offset_per_nbh,
                             aes(label = paste(nta, " - ", 
                                               label_percent(accuracy=0.01)(proportion),
                                       sep=""),
                                 x = nta_name,
                                 y = ifelse(nta=="MN50", 100*proportion+22,
                                            100*proportion-22)),
                             size=2.2, color="white", hjust=1)

#curb_loc_per_nbh %>%
#	arrange(desc(curb_loc), desc(proportion)) %>%
#	mutate(number_of_trees = prettyNum(number_of_trees, big.mark=",")) %>%
#	select(-proportion)

Biological

Size: In terms of trunk diameter, the mean size of the tree population (red line in Fig. 5) is $8.6312$ inches, with a standard deviation of $5.5906$. Furthermore, its distribution is positively skewed, implying that the majority of trees have trunk diameters closer to the lower bound. In this case, we can use the median (blue line) of $8$ inches (with an IQR of $7$) as a better measure of central tendency (and spread).

defaultW <- getOption("warn")
options(warn=-1)

# Summary statistics of the trunk diameter
tree_dbh_stats <- data.frame(N = length(trees$tree_dbh),
    						 mean = mean(trees$tree_dbh),
                             sd = sd(trees$tree_dbh),
                             min = min(trees$tree_dbh),
                             first_quartile = quantile(trees$tree_dbh, probs = 0.25),
                             median = median(trees$tree_dbh),
                             second_quartile = quantile(trees$tree_dbh, probs = 0.75),
                             max = max(trees$tree_dbh))
row.names(tree_dbh_stats) <- "tree_dbh" 

# HTML Table for Tree Size
#kable(tree_dbh_stats %>%
#	mutate_if(is.numeric, list(~prettyNum(., big.mark=",")))
#     "html", caption = "Table _: Summary statistics of the tree diameter")

# Density curve for 'tree_dbh'
tree_dbh_dist_plot <- ggplot(trees, aes(x = tree_dbh)) + 
	geom_histogram(aes(y = after_stat(density)),
                   binwidth=1.1,
                   color=1,
                   fill="#5FBD5F") +
	geom_density(linewidth=0.85,
                 linetype=1,
                 colour = muted("5FBD5F"),
                 alpha=0.5) +

# Plot mean and median
geom_vline(aes(xintercept = mean(tree_dbh)), col="red", size=0.6) +
geom_vline(aes(xintercept = median(tree_dbh)), col="blue", size=0.6) +

     theme(axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color="#65707C",
                                   size=12,
                                   family="sans serif"),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.subtitle = element_text(color="#65707C",
                                    hjust=0.15,
                                    size=10,
                                    family="sans serif"),
          plot.title = element_text(color="#65707C",
                                    hjust=0.20,
                                    size=14,
                                    family="sans serif")) +
	ggtitle("\nFig. 5: Distribution of the Trunk Diameter") +
	labs(x="\nTrunk diameter in inches\n", y="\nDensity\n",
         subtitle="                (measured at 54 inches above the ground)\n") +
	scale_x_continuous(expand = c(0.01, 0), 
                       limits = c(0, 105),
                       breaks = seq(0, 105, by=10)) +
	scale_y_continuous(expand = c(0.01, 0),
                       limits = c(0, 0.12), 
                       breaks = seq(0, 0.12, by=0.02))
#tree_dbh_stats %>%
#	mutate_if(is.numeric, list(~round(., digits=4))) %>%
#	mutate_if(is.numeric, list(~prettyNum(., big.mark=",")))

options(warn = defaultW)
ggsave("dbh_dist.png", plot = tree_dbh_dist_plot, width = 6, height = 4, dpi = 300)
Warning message:
“Removed 5 rows containing non-finite outside the scale range (`stat_bin()`).”
Warning message:
“Removed 5 rows containing non-finite outside the scale range
(`stat_density()`).”
Warning message:
“Removed 3 rows containing missing values or values outside the scale range
(`geom_bar()`).”

Health-Related: Nearly all of the trees in Manhattan have an “Alive” status, and majority are in a “Good” health condition. On the other hand, the minority of trees have problems with their roots, trunks, and branches. The most notable among these respective tree parts are caused by paving stones in the tree bed; trunk problems other than by wires/ropes and installed lighting; and branch problems other than by lights/wires and shoes.

# Status and health 
pop_status <- as.data.frame(table(trees$status)) %>%
	mutate(attribute = "status", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_health <- as.data.frame(table(trees$health)) %>%
	mutate(attribute = "health", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything()) %>%
	arrange(desc(proportion))

# Root problems
pop_root_stone <- as.data.frame(table(trees$root_stone)) %>%
	mutate(attribute = "root_stone", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_root_grate <- as.data.frame(table(trees$root_grate)) %>%
	mutate(attribute = "root_grate", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_root_other <- as.data.frame(table(trees$root_other)) %>%
	mutate(attribute = "root_other", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())

# Trunk problems
pop_trunk_wire <- as.data.frame(table(trees$trunk_wire)) %>%
	mutate(attribute = "trunk_wire", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_trnk_light <- as.data.frame(table(trees$trnk_light)) %>%
	mutate(attribute = "trnk_light", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_trnk_other <- as.data.frame(table(trees$trnk_other)) %>%
	mutate(attribute = "trnk_other", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())

# Branch problems
pop_brch_light <- as.data.frame(table(trees$brch_light)) %>%
	mutate(attribute = "brch_light", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_brch_shoe <- as.data.frame(table(trees$brch_shoe)) %>%
	mutate(attribute = "brch_shoe", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_brch_other <- as.data.frame(table(trees$brch_other)) %>%
	mutate(attribute = "brch_other", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())

# Tree population's attributes
pop_attributes <- bind_rows(pop_status,
                            pop_health,
                            pop_root_stone,
                            pop_root_grate,
                            pop_root_other,
                            pop_trunk_wire,
                            pop_trnk_light,
                            pop_trnk_other,
                            pop_brch_light,
                            pop_brch_shoe,
                            pop_brch_other) %>%
                  mutate(percentage = label_percent(accuracy = 0.01)(proportion))  				  
# Highest category per attribute
pop_attributes_highest_per_category <- pop_attributes %>%
	group_by(attribute) %>%
	filter(proportion == max(abs(proportion)))

# Order by attributes 
pop_attributes$attribute <- factor(
    pop_attributes$attribute,
       levels = rev(unique(pop_attributes$attribute)),
       ordered=TRUE
)

# Order by categories 
pop_attributes$category <- factor(
    pop_attributes$category,
       levels = c("Dead", "Alive", "Fair", "Poor", "Good", "Yes", "No"),
       ordered=TRUE
)

pop_attributes_stacked_bar_plot <- ggplot(pop_attributes) + 
	geom_chicklet(aes(x = attribute, y = proportion*100, fill = category), 
                  radius = grid::unit(0.75, "mm"), position="stack") +
	coord_flip() +
	theme(legend.position = "right",
          legend.justification="top",
          legend.direction="vertical",
          legend.key.size = unit(0, "pt"),
          legend.key = element_rect(fill = NA),
          legend.text = element_text(margin = margin(r = 4, unit = "pt"),
                                     color = "#65707C",
                                     family="sans serif"),
          legend.title = element_text(color = "#65707C",
                                      face = "bold",
                                      size = 9,
                                      family="sans serif"),
		  axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color="#65707C",
                                   size=12,
                                   family="sans serif"),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.title = element_text(color = "#65707C",
                                    hjust = 0.715,
                                    size= 13.75,
                                    family = "sans serif")) +
	scale_x_discrete(labels=c("Other problems (branch)",
                              "Shoes (branch)",
                              "Lights or wires (branch) ",
                              "Other problems (trunk)",
                              "Lighting installed (trunk)",
                              "Wires or rope (trunk)",
                              "Other problems (root)",
                              "Metal grates (root)",
                              "Paving stones (root)",
                              "Health",
                              "Status"))+
	scale_fill_manual(values = c("grey40",
                                 "#10401B",
                                 "#89E7B3",
								 "#40C17E",
                                 "#1F9153",
                                 "#9F2305",
                                 "#4E7A61"),
                     labels = c("Dead", "Alive", "Poor",  "Fair", "Good", "Yes", "No")) +
	ggtitle("\nFig. 6: Proportional Stacked Bar Graph of the Tree Population's Attributes\n") +
	labs(x="\nAttribute \n", y="\n%  \n(Number of trees) \n", fill="Category: ") +
    guides(fill = guide_legend(ncol=1,
                               override.aes = list(shape = 15,
                                                   size = 4))) +
	scale_y_continuous(expand = c(0.01, 0),
                       breaks = seq(0, 100, by=10)) +
	ggrepel::geom_text_repel(data = pop_attributes_highest_per_category,
                             aes(label = paste(percentage,
                                       "\n (", prettyNum(number_of_trees,
                                                  big.mark=","),")",
                                       sep=""),
                                 x = attribute,
                                 y = 100*proportion-20),
                             size=3, color="white", hjust=1)

#pop_attributes %>%
#	mutate(number_of_trees = prettyNum(number_of_trees, big.mark=",")) %>%
#	select(-proportion)
pop_attributes_stacked_bar_plot
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)):
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”
Warning message in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
“font family 'sans serif' not found in PostScript font database”

png

trees %>%
	summarize(total_number_of_censused_trees = n())

trees %>%
	group_by(spc_common) %>%
	summarize(number_of_trees_per_species = n()) %>%
	filter(!is.na(spc_common)) %>%
	summarize(number_of_identified_species = n())

trees %>%
	filter(is.na(spc_common)) %>%
	summarize(number_of_trees_with_unidentified_species = n()) %>%
	mutate(number_of_trees_with_identified_species = nrow(trees) - number_of_trees_with_unidentified_species) 
A tibble: 1 × 1
total_number_of_censused_trees
<int>
64229
A tibble: 1 × 1
number_of_identified_species
<int>
128
A tibble: 1 × 2
number_of_trees_with_unidentified_speciesnumber_of_trees_with_identified_species
<int><int>
180162428
nbh_spc_long <- nta_spc %>%
	rownames_to_column("nta") %>% 
	pivot_longer(cols = 2:129, 
                 names_to = "spc_common",
                 values_to = "number_of_trees") %>%
	inner_join(trees %>% select(nta, nta_name) %>% distinct(nta, nta_name), by = "nta")

top_spc_per_nbh <- nbh_spc_long %>%
	group_by(nta) %>%
	top_n(1, number_of_trees) %>%
	arrange(nta, desc(number_of_trees)) %>%
	select(contains("nta"), everything()) %>%
	mutate(percentage = label_percent(accuracy=0.01)(
           number_of_trees/length(trees$tree_id)))

top_spc_per_nbh_short <- top_spc_per_nbh %>%
	group_by(spc_common) %>% 
    mutate(nta = paste0(nta, collapse = ", "),
           nta_name = paste0(nta_name, collapse = ", ")) %>%
	count(nta, nta_name, spc_common) %>%
	arrange(desc(n)) %>%
    select(nta, nta_name, spc_common, n) %>%
	mutate(percentage = label_percent(accuracy=0.01)(n/28)) %>% 
	rename(number_of_nta = n, most_common_spc = spc_common) 

# HTML Table for the counts of neighborhood for the most common species
#kable(top_spc_per_nbh_short,
#   "html", caption = " ")

#Counts of neighborhood for the most common species
spc_in_top_ten_per_nbh <- nbh_spc_long %>%
	group_by(nta) %>%
	top_n(10, number_of_trees) %>%
	arrange(nta, desc(number_of_trees)) %>%
	select(contains("nta"), everything()) %>%
	ungroup() %>%
	count(spc_common) %>%
	mutate(percentage = label_percent(accuracy=0.01)(n/28)) %>% 
	arrange(desc(n)) %>%   
	rename(number_of_nta = n)
####################################
#### Characteristics by species ####
####################################

## Location ##

# Location in relation with the curb 
spc_curb_loc <- as.data.frame.matrix(table(trees$spc_common, trees$curb_loc)) %>%
	rename_with( ~ paste0(.x, "_loc"))

## Biology ##

# Tree size (in terms of trunk diameter)
spc_tree_dbh <- as.data.frame.matrix(table(trees$spc_common, trees$tree_dbh)) %>%
	rename_with( ~ paste0(.x, "_tree_dbh"))

# Status and health 
spc_status <- as.data.frame.matrix(table(trees$spc_common, trees$status)) #%>%
	#rename_with( ~ paste0(.x, "_status"))
spc_health <- as.data.frame.matrix(table(trees$spc_common, trees$health)) #%>%
	#rename_with( ~ paste0(.x, "_health"))

# Root problems
spc_root_stone <- as.data.frame.matrix(table(trees$spc_common, trees$root_stone)) %>%
	rename_with( ~ paste0(.x, "_root_stone"))
spc_root_grate <- as.data.frame.matrix(table(trees$spc_common, trees$root_grate)) %>%
	rename_with( ~ paste0(.x, "_root_grate"))
spc_root_other <- as.data.frame.matrix(table(trees$spc_common, trees$root_other)) %>%
	rename_with( ~ paste0(.x, "_root_other"))

# Trunk problems
spc_trunk_wire <- as.data.frame.matrix(table(trees$spc_common, trees$trunk_wire)) %>%
	rename_with( ~ paste0(.x, "_trunk_wire"))
spc_trnk_light <- as.data.frame.matrix(table(trees$spc_common, trees$trnk_light)) %>%
	rename_with( ~ paste0(.x, "_trnk_light"))
spc_trnk_other <- as.data.frame.matrix(table(trees$spc_common, trees$trnk_other)) %>%
	rename_with( ~ paste0(.x, "_trnk_other"))

# Branch problems
spc_brch_light <- as.data.frame.matrix(table(trees$spc_common, trees$brch_light)) %>%
	rename_with( ~ paste0(.x, "_brch_light"))
spc_brch_shoe <- as.data.frame.matrix(table(trees$spc_common, trees$brch_shoe)) %>%
	rename_with( ~ paste0(.x, "_brch_shoe"))
spc_brch_other <- as.data.frame.matrix(table(trees$spc_common, trees$brch_other)) %>%
	rename_with( ~ paste0(.x, "_brch_other"))
trees %>% group_by(spc_common) %>% filter(spc_common != 'null') %>% count() %>% ungroup() %>% mutate(perc=round(n*100/sum(n),2)) %>% arrange(desc(n))
A tibble: 128 × 3
spc_commonnperc
<chr><int><dbl>
Honeylocust1317621.11
Callery pear 729711.69
Ginkgo 5859 9.39
Pin oak 4584 7.34
Sophora 4453 7.13
London planetree 4122 6.60
Japanese zelkova 3596 5.76
Littleleaf linden 3333 5.34
American elm 1698 2.72
American linden 1583 2.54
Northern red oak 1143 1.83
Willow oak 889 1.42
Cherry 869 1.39
Chinese elm 785 1.26
Green ash 770 1.23
Swamp white oak 681 1.09
Silver linden 541 0.87
Crab apple 437 0.70
Golden raintree 359 0.58
Red maple 356 0.57
Sawtooth oak 353 0.57
Kentucky coffeetree 348 0.56
Norway maple 290 0.46
Black locust 259 0.41
White oak 241 0.39
Sweetgum 227 0.36
Hawthorn 219 0.35
Shingle oak 205 0.33
Dawn redwood 199 0.32
English oak 197 0.32
Two-winged silverbell80.01
American larch70.01
Eastern hemlock70.01
Southern red oak70.01
Crimson king maple60.01
European beech60.01
Himalayan cedar60.01
Arborvitae50.01
Bigtooth aspen50.01
Crepe myrtle50.01
Pitch pine50.01
Blue spruce40.01
Black pine30.00
Cockspur hawthorn30.00
Norway spruce30.00
Pine30.00
Virginia pine30.00
Boxelder20.00
Douglas-fir20.00
European alder20.00
Quaking aspen20.00
Scots pine20.00
Osage-orange10.00
Persian ironwood10.00
Pignut hickory10.00
Red horse chestnut10.00
Red pine10.00
Smoketree10.00
Spruce10.00
White pine10.00

Tree Species

Using spatial, descriptive, and correlation analyses, the following information outlines the biodiversity, biology, and ranking in terms of desirable traits of the tree species in Manhattan:

Biodiversity

Richness

Richness is referred to as the number of species within a defined region. With respect to Manhattan, ${128}$ species were identified among ${N_{I} =62,428}$ trees, while the remaining ${N_{U} = 1,801}$ have species which are unidentified in the census. In terms of the neighborhoods, the ten with the highest richness (of identified species) are:

  1. Washington Heights North (MN35)
  2. Lower East Side (MN28)
  3. Washington Heights South (MN36)
  4. West Village (MN23)
  5. Central Harlem North-Polo Grounds (MN03)
  6. Hamilton Heights (MN04)
  7. Upper West Side (MN12)
  8. Upper East Side-Carnegie Hill (MN40)
  9. Central Harlem South (MN11)
  10. East Village (MN22)
defaultW <- getOption("warn")
options(warn=-1)

# Top 10 NTAs with the highest species richness
top_ten_nbh_rchns <- nbh_rchns %>%
	slice(1:10) %>%
	rownames_to_column("rank")

# HTML Table for Top 10 Most Abundant Species
#kable(for_table_nbh_rchns, 
#      caption = " ",
#      label = "tables", format = "html", booktabs = TRUE)

# Order by richness
nbhs_map$nta_and_rchns <- factor(
    nbhs_map$nta_and_rchns,
       levels = (nbhs_map %>% arrange(desc(richness)))$nta_and_rchns,
       ordered = TRUE
)

# Map of NTAs' richness
nbh_rchns_map_plot <- ggplot() + 
	geom_sf(data = nbhs_map %>% filter(borough != "MN" | nta == "MN99"),
            fill="#E8EAED", color="grey") +
	geom_sf(data = nbhs_map %>% filter(borough == "MN", nta != "MN99"),
            aes(fill = richness,
                color = nta_and_rchns
               )
           ) + 
    stat_sf_coordinates(data = nbhs_map %>% filter(borough == "MN", nta != "MN99") %>%
            	        	inner_join(nbh_rchns, by = c("nta", "nta_name")) %>%
                        	filter(nta %in% top_ten_nbh_rchns$nta),
                        color="grey25", size = 0.5) +
    theme(legend.position = c(0.3518, 0.5), 
          legend.justification=0.0,
          legend.key.width = unit(2.5, 'mm'),
	      legend.key.height = unit(1.8, 'mm'), 
          legend.direction="vertical",
          legend.background = element_roundrect(r = grid::unit(0.02, "snpc"),
                                               fill = alpha("#FFFFFF", 0.90)),
          legend.key = element_rect(fill=NA),
          legend.text = element_text(margin = margin(r=5, unit="pt"),
        	                         color="#65707C",
                                     family="sans serif"),
          legend.title = element_text(face="bold",
                                      color="#65707C",
                                      size=8.5,
                                      family="sans serif"),
          axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color="#65707C",
                                   size=7,
                                   family="sans serif"),
          axis.text.x = element_text(angle=90,
                                     vjust=0.5,
                                     hjust=1),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          
          panel.border = element_rect(color="grey40",
                                      fill=NA),  
          panel.spacing = unit(2, "lines"),
          panel.background  = element_roundrect(r = grid::unit(0.001, "snpc"),
                                               fill = alpha("#9CC0F9", 1)),
          plot.title = element_text(color="#65707C",
                                    hjust=1.8,
                                    vjust=10,
                                    size=14,
                                    family="sans serif")) +
		 labs(x="", y="", color="    Code - Richnesss : Name"
             ) +
		 ggtitle("Fig. 7: Map of Tree Species Richness of Manhattan's Neighborhoods") +
	scale_x_continuous(expand = c(0.01, 0),
                       limits = c(-74.04, -73.64), 
                       breaks = seq(-74.04, -73.64, by=0.02)) +
	scale_y_continuous(expand = c(0.01, 0),
                       limits = c(40.68, 40.88), 
                       breaks = seq(40.68, 40.88, by=0.02)) +
	scale_color_manual(values = replicate(28, "grey25")) +
	scale_fill_gradient2(low = "#E3EDE5",
                         high = "#068409") +
	ggrepel::geom_label_repel(data = nbhs_map %>% filter(nta %in% top_ten_nbh_rchns$nta),
                              aes(label = nta, geometry = geometry),
                              stat="sf_coordinates",
                              min.segment.length=0,
                              label.size=NA,
                              alpha=0.5) +
	coord_sf(xlim = c(-74.04, -73.64), ylim = c(40.68, 40.88))     

# Extract NTA fill colors
color_scheme_3 <- as.data.frame(ggplot_build(nbh_rchns_map_plot)$data[[2]])$fill

nbh_rchns_map_plot2 <- nbh_rchns_map_plot +
	guides(fill = "none",
           color = guide_legend(ncol=1,
                                override.aes = list(color = NA,
                                                    fill = color_scheme_3,
                                                    linewidth=0))
          )

options(warn = defaultW)
top_ten_nbh_rchns
A tibble: 10 × 4
rankntanta_namerichness
<chr><chr><chr><int>
1MN35Washington Heights North81
2MN28Lower East Side78
3MN36Washington Heights South77
4MN23West Village76
5MN03Central Harlem North-Polo Grounds75
6MN04Hamilton Heights73
7MN12Upper West Side73
8MN40Upper East Side-Carnegie Hill73
9MN11Central Harlem South71
10MN22East Village68

Abundance

In this context, abundance is defined as the number of Manhattan trees per species, while relative abundance is the share of trees a certain species has in relation to the total number of trees in Manhattan. Among the $128$ and other unidentified tree species in Manhattan, the ten most abundant are:

  1. Honeylocust
  2. Callery pea
  3. Ginkgo
  4. Pin oak
  5. Sophora
  6. London planetree
  7. Japanese zelkova
  8. Littleleaf linden
  9. American elm
  10. American linden
spc_abd %>% mutate(round(relative_abundance*100,2))
Error: object 'spc_abd' not found
Traceback:


1. mutate(., round(relative_abundance * 100, 2))

2. .handleSimpleError(function (cnd) 
 . {
 .     watcher$capture_plot_and_output()
 .     cnd <- sanitize_call(cnd)
 .     watcher$push(cnd)
 .     switch(on_error, continue = invokeRestart("eval_continue"), 
 .         stop = invokeRestart("eval_stop"), error = NULL)
 . }, "object 'spc_abd' not found", base::quote(eval(expr, envir)))
# Species abundance and relative abundance
spc_abd <- trees %>% 
	filter(spc_common != "null") %>%
	group_by(spc_common) %>%
	summarize(abundance = n()) %>%  
	ungroup() %>%
	mutate(relative_abundance = abundance/sum(abundance)) %>%
	arrange(desc(abundance))

# Table for Top 10 Most Abundant Species
for_table_spc_abd <- spc_abd %>%
	slice(1:10) %>%
	rownames_to_column("rank") %>%
	mutate(abundance = prettyNum(abundance,big.mark=","),
           perc_relative_abundance = label_percent(accuracy=0.01)(relative_abundance))

# HTML Table for Top 10 Most Abundant Species
#kable(for_table_spc_abd, 
#      caption = " ",
#      label = "tables", format = "html", booktabs = TRUE)

# Bar graph for Top 25 tree species
top_species_bar_plot <- ggplot(spc_abd %>% slice(1:25)) + 
	geom_chicklet(aes(x = fct_reorder(spc_common,
                                    abundance),
                      y = abundance), 
                  fill="#10401B",
                  radius = grid::unit(1, "mm"), position="stack") +
	coord_flip() +
	theme(legend.position="none",
          axis.title = element_text(color = "#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color = "#65707C",
                                   size=12,
                                   family="sans serif"),
          axis.title.x = element_text(margin=margin(20,0,10,0)),
          axis.title.y = element_text(margin=margin(0,20,0,10)),
          axis.line = element_line(colour = "grey",
                                   linewidth = 0.5),
          panel.grid.major = element_line(color = "grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.title = element_text(color = "#65707C",
                                    hjust = 1.03,
                                    vjust = 4,
                                    size= 14,
                                    family = "sans serif",
                                    margin=margin(0,0,20,0))) +
	ggtitle("
\nFig. 8: Bar Graph of the 25 Most Abundant Tree Species in Manhattan ") +
	labs(x="Common name of the species", y="Abundance (% relative abundance)") +
	scale_y_continuous(expand = c(0.01, 0), limits = c(0,13500),
                      breaks = seq(0, 13500, by=2000)) +
	geom_text(aes(label = paste(prettyNum(abundance, big.mark=","),
                                " (", label_percent(accuracy=0.01)(relative_abundance),")",
                                sep=""),
                                 x = spc_common,
                                 y = ifelse(between(rank(desc(abundance)),3,10), abundance-807.5,
                                           ifelse(between(rank(desc(abundance)),2,2), abundance-880,
                                           ifelse(between(rank(desc(abundance)),1,1), abundance-980,
                                           ifelse(between(rank(desc(abundance)),11,11), abundance+770,
                                           abundance+670)))),
                  color = ifelse(between(rank(desc(abundance)),1,10), "white",
                                           "#65707C")),
              size = 2) +
scale_color_manual(values=c("#65707C","white"))

#spc_abd %>%
#mutate(abundance = prettyNum(abundance,big.mark=","),
#         perc_relative_abundance = label_percent(accuracy=0.01)(relative_abundance)) %>%select(-relative_abundance)

You can see in more details using the table below the species and their abundances (and relative abundances) with respect to the neighborhoods they belong to:

spc_abd_nbh <- nbh_spc_long %>%
	group_by(nta, nta_name) %>%
	filter(!(number_of_trees == 0)) %>%
	rename(abundance_wrt_nta = number_of_trees) %>%
	select(starts_with("nta"), spc_common, everything()) %>%
	mutate(relative_abundance_wrt_nta = label_percent(accuracy=0.01)(abundance_wrt_nta/sum(abundance_wrt_nta))) %>% 
	arrange(nta, desc(abundance_wrt_nta)) %>%
	ungroup()

spc_abd_nbh
A tibble: 1664 × 5
ntanta_namespc_commonabundance_wrt_ntarelative_abundance_wrt_nta
<chr><chr><chr><int><chr>
MN01Marble Hill-InwoodJapanese zelkova22515.65%
MN01Marble Hill-InwoodHoneylocust17512.17%
MN01Marble Hill-InwoodSophora1319.11%
MN01Marble Hill-InwoodGinkgo1158.00%
MN01Marble Hill-InwoodPin oak1107.65%
MN01Marble Hill-InwoodLittleleaf linden1047.23%
MN01Marble Hill-InwoodCallery pear 745.15%
MN01Marble Hill-InwoodAmerican linden 614.24%
MN01Marble Hill-InwoodAmerican elm 483.34%
MN01Marble Hill-InwoodNorthern red oak 483.34%
MN01Marble Hill-InwoodLondon planetree 463.20%
MN01Marble Hill-InwoodSawtooth oak 292.02%
MN01Marble Hill-InwoodSilver linden 261.81%
MN01Marble Hill-InwoodSwamp white oak 191.32%
MN01Marble Hill-InwoodGreen ash 181.25%
MN01Marble Hill-InwoodNorway maple 171.18%
MN01Marble Hill-InwoodWillow oak 171.18%
MN01Marble Hill-InwoodShingle oak 130.90%
MN01Marble Hill-InwoodSassafras 120.83%
MN01Marble Hill-InwoodTulip-poplar 110.76%
MN01Marble Hill-InwoodCherry 100.70%
MN01Marble Hill-InwoodCommon hackberry 90.63%
MN01Marble Hill-InwoodDawn redwood 80.56%
MN01Marble Hill-InwoodRed maple 80.56%
MN01Marble Hill-InwoodAmerican hophornbeam 70.49%
MN01Marble Hill-InwoodBlack walnut 70.49%
MN01Marble Hill-InwoodChinese tree lilac 70.49%
MN01Marble Hill-InwoodEmpress tree 70.49%
MN01Marble Hill-InwoodEastern hemlock 60.42%
MN01Marble Hill-InwoodJapanese snowbell 50.35%
MN40Upper East Side-Carnegie HillHedge maple 10.02%
MN40Upper East Side-Carnegie HillHorse chestnut 10.02%
MN40Upper East Side-Carnegie HillJapanese maple 10.02%
MN40Upper East Side-Carnegie HillJapanese snowbell 10.02%
MN40Upper East Side-Carnegie HillMulberry 10.02%
MN40Upper East Side-Carnegie HillPagoda dogwood 10.02%
MN40Upper East Side-Carnegie HillPaper birch 10.02%
MN40Upper East Side-Carnegie HillSouthern red oak 10.02%
MN40Upper East Side-Carnegie HillTwo-winged silverbell 10.02%
MN50Stuyvesant Town-Cooper VillageHoneylocust27963.70%
MN50Stuyvesant Town-Cooper VillageLondon planetree 8118.49%
MN50Stuyvesant Town-Cooper VillageJapanese zelkova 112.51%
MN50Stuyvesant Town-Cooper VillageSophora 112.51%
MN50Stuyvesant Town-Cooper VillageGinkgo 61.37%
MN50Stuyvesant Town-Cooper VillagePin oak 61.37%
MN50Stuyvesant Town-Cooper VillageAmerican linden 51.14%
MN50Stuyvesant Town-Cooper VillageCallery pear 51.14%
MN50Stuyvesant Town-Cooper VillageCommon hackberry 51.14%
MN50Stuyvesant Town-Cooper VillageLittleleaf linden 51.14%
MN50Stuyvesant Town-Cooper VillageSwamp white oak 51.14%
MN50Stuyvesant Town-Cooper VillageKentucky coffeetree 40.91%
MN50Stuyvesant Town-Cooper VillageAmerican elm 30.68%
MN50Stuyvesant Town-Cooper VillageNorthern red oak 30.68%
MN50Stuyvesant Town-Cooper VillageWhite oak 30.68%
MN50Stuyvesant Town-Cooper VillageAmur maackia 10.23%
MN50Stuyvesant Town-Cooper VillageAmur maple 10.23%
MN50Stuyvesant Town-Cooper VillageGreen ash 10.23%
MN50Stuyvesant Town-Cooper VillageSawtooth oak 10.23%
MN50Stuyvesant Town-Cooper VillageShingle oak 10.23%
MN50Stuyvesant Town-Cooper VillageTree of heaven 10.23%
Diversity

To describe the overall species diversity in Manhattan, a quantitative measure called Simpson’s Diversity Index $(SDI)$ is used, which takes into account the species richness and evenness (or the distribution of abundance across the tree species in a community). The formula is given by:

${D} = {1- \frac{\sum \limits _{i=1} ^{128} n_{i}({n_{i}-1})} {N_{I}({N_{I}-1})} } $


where ${D}$ = Simpson’s Diversity Index $(SDI)$;
           ${n_{i}}$ = ${i^{th}}$ species abundance;
          ${N_{I}}$ = number of trees with identified species = ${62,428}$

With that, the computed $SDI$ value is $0.909$. This means that there is a very high diversity of tree species in Manhattan, and the chance of distinct species among two randomly selected trees from a sample is $90.9\%$.

# Simpson's Diversity Index (SDI)
mnh_sdi <- spc_abd %>%
	filter(!is.na(spc_common)) %>%
	 select(-relative_abundance) %>%
	 mutate(numerator = abundance*(abundance-1)) %>%
	 summarize(SDI = 1-(sum(numerator)/(sum(abundance)*(sum(abundance)-1))),
               number_of_trees = sum(abundance),
               richness = n())

Biology

Size: Tree sizes of the species were compared through their median trunk diameter at breast height $(DBH)$.

Fig. 9 shows the Top 25 largest species in terms of this metric:

# The table below shows each species' summary statistics and is arranged by descending median $dbh$, while 

# Summary statistics of species' tree dbh
spc_tree_dbh_stats <- trees %>% 
	group_by(spc_common) %>%
	filter(!is.na(spc_common), !is.na(tree_dbh)) %>%
	summarize(abundance = n(),
              mean_tree_dbh = mean(tree_dbh),
              sd_tree_dbh = sd(tree_dbh),
              min_tree_dbh = min(tree_dbh),
              first_quartile_tree_dbh = quantile(tree_dbh, probs=0.25),
              median_tree_dbh = median(tree_dbh),
              third_quartile_tree_dbh = quantile(tree_dbh, probs=0.75),
              max_tree_dbh = max(tree_dbh))  %>%
	arrange(desc(median_tree_dbh))

# Top 25 species in terms of median dbh
top_spc_tree_dbh_stats <- spc_tree_dbh_stats #%>%
	#filter out species with abundances less than the median abundances
#filter(abundance >= median(abundance)) %>%
#select(spc_common, abundance, median_tree_dbh, everything())

# Bar graph for Top 30 tree species
top_spc_dbh_plot <- ggplot(top_spc_tree_dbh_stats %>% slice(1:25)) + 
	geom_chicklet(aes(x = fct_reorder(spc_common,
                                    median_tree_dbh),
                      y = median_tree_dbh), 
                  fill="#10401B",
                  radius = grid::unit(1, "mm"), position="stack") +
	coord_flip() +
	theme(axis.title = element_text(color = "#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color = "#65707C",
                                   size=12,
                                   family="sans serif"),
          axis.title.x = element_text(margin=margin(20,0,10,0)),
          axis.title.y = element_text(margin=margin(0,20,0,10)),
          axis.line = element_line(colour = "grey",
                                   linewidth = 0.5),
          panel.grid.major = element_line(color = "grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.title = element_text(color="#65707C",
                                    hjust=1.13,
                                    size=14,
                                    family="sans serif"),
          plot.subtitle = element_text(color="#65707C",
                                    hjust=2.02,
                                    size=10,
                                    family="sans serif")) +   
	ggtitle("\nFig. 9: Bar Graph of the Top 25 Largest Tree Species in Manhattan",
            subtitle="(in terms of median trunk diameter at breast height (DBH) of 54 inches)\n") +
	labs(x="\nCommon name of the species\n", y="Trunk diameter in inches\n") +
	scale_y_continuous(expand = c(0.01, 0),
                       limits = c(0, 15.5),
                       breaks = seq(0, 15.5, by=3)) +
	geom_text(aes(label = median_tree_dbh,
                                 x = spc_common,
                                 y = median_tree_dbh-0.4),
              size = 3, color = "white")

#spc_tree_dbh_stats %>% mutate_if(is.numeric, #list(~prettyNum(., big.mark=","))) %>% select(spc_common, abundance, #median_tree_dbh, everything())

#summary(lm(spc_tree_dbh_stats$abundance~spc_tree_dbh_stats$median_tree_dbh))
#shapiro.test(lm(spc_tree_dbh_stats$abundance~spc_tree_dbh_stats$median_tree_dbh)$residuals)
#abd_dbh_corr <- cor(spc_tree_dbh_stats$abundance, spc_tree_dbh_stats$median_tree_dbh, method="kendall")
#abd_dbh_corr

Health-Related: Out of the $128$ species that have been identified, $127$ have $100\%$ of their trees being alive, while the remaining one, honeylocust, has $99.99\%$. As for the health, a numerical value called health index $(HI)$ was computed for each species. This was done by assigning a number, ${j} ∈ {1,2,3}$, to the categories of “$Poor$”, “$Fair$”, and “$Good$” health, respectively, and then using the formula:

${HI_{i}} = \frac {\sum \limits _{j=1} ^{3} j{a}_{j}}{3 n_{i}} $


where ${HI_{i}}$ = health index of the $i^{th}$ species;
              ${a_{j}}$ = species abundance with respect to the $j^{th}$ health category;
              ${n_{i}}$ = ${i^{th}}$ species abundance

Fig. 10 shows the $25$ species with the highest $HI$ value as well as the distribution of their relative abundances across health categories.

# Status per species
spc_status <- trees %>% 
	filter(!(is.na(spc_common) | is.na(spc_common))) %>%
	group_by(spc_common, status) %>%
	summarize(number_of_trees = n(), .groups="keep") %>%
	group_by(spc_common) %>%
	mutate(proportion_wrt_spc = number_of_trees/sum(number_of_trees),
           percentage_wrt_spc = label_percent(accuracy=0.01)(proportion_wrt_spc)) %>%
	arrange(proportion_wrt_spc) %>%
	select(-proportion_wrt_spc) %>%
	ungroup()
# Health per species
spc_health <- trees %>% 
	filter(!is.na(spc_common), !is.na(health)) %>%
	group_by(spc_common, health) %>%
	summarize(number_of_trees = n(), .groups="keep") %>%
	group_by(spc_common) %>%
	mutate(proportion = number_of_trees/sum(number_of_trees),
           percentage = label_percent(accuracy=0.01)(proportion),
           health = as.factor(health)) %>%
	arrange(spc_common, desc(proportion)) %>%
	ungroup()


spc_health_index <- spc_health %>%
	group_by(spc_common) %>%
	mutate(health_score = ifelse(health=="Good", 3*number_of_trees,
                                 ifelse(health=="Fair", 2*number_of_trees,
                                        1*number_of_trees)),
          health_index = sum(health_score)/(3*sum(number_of_trees))) %>%
	ungroup() %>%
	select(spc_common, number_of_trees, health_index) %>%
	group_by(spc_common) %>%
	mutate(number_of_trees = sum(number_of_trees)) %>%
	distinct(spc_common, number_of_trees, health_index) %>%
	arrange(desc(health_index)) %>%
	ungroup() %>%
	rename(abundance = number_of_trees)

for_graph_top_spc_health <- spc_health %>%
	filter(spc_common %in% (
        spc_health_index %>%
        #filter out species with abundances less than the median abundances
#filter(abundance >= median(spc_tree_dbh_stats$abundance)) %>% 
                            	top_n(25, health_index))$spc_common) %>%
	arrange(desc(proportion))

# Order health per species
for_graph_top_spc_health$health <- factor(
    for_graph_top_spc_health$health,
    levels = c("Poor", "Fair", "Good"),
    ordered = TRUE
)

# Order species by proportion of 'Good' health
for_graph_top_spc_health$spc_common <- factor(
    for_graph_top_spc_health$spc_common,
    levels = rev((for_graph_top_spc_health %>% filter(health == "Good"))$spc_common),
    ordered = TRUE
)

top_spc_health_highest <- for_graph_top_spc_health %>% 
	group_by(spc_common) %>%
	filter(proportion == max(abs(proportion)))

top_spc_health_stacked_bar_plot <- ggplot(for_graph_top_spc_health) + 
	geom_chicklet(aes(x = spc_common, y = proportion*100, fill = health), 
                  radius = grid::unit(0.75, "mm"), position="stack") +
	coord_flip() +
	theme(legend.position = "right",
          legend.justification="top",
          legend.direction="vertical",
          legend.key.size = unit(0, 'pt'),
          legend.key = element_rect(fill = NA),
          legend.text = element_text(margin = margin(r = 4, unit = "pt"),
                                     color = "#65707C",
                                     family="sans serif"),
          legend.title = element_text(color = "#65707C",
                                      face="bold",
                                      size = 9,
                                      family="sans serif"),
		  axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text.x = element_text(color="#65707C",
                                   size=6,
                                   family="sans serif"),
          axis.text.y = element_text(color="#65707C",
                                   size=10,
                                   family="sans serif"),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.subtitle = element_text(color="#65707C",
                                    hjust=-2.07,
                                    size=10,
                                    family="sans serif"),
          plot.title = element_text(color = "#65707C",
                                    hjust = 0.74,
                                    size= 12,
                                    family = "sans serif")) +
	scale_fill_manual(values = c("#89E7B3",
								 "#40C17E",
                                 "#1F9153")) +     
	ggtitle("\nFig. 10: Proportional Stacked Bar Graph of the Top 25 Healthiest Tree Species",
            subtitle="               (in terms of health index (HI) value)\n") +
	labs(x="\nCommon name of the species\n", y="\n% relative abundance\n", fill="Health: ") +
    guides(fill = guide_legend(ncol=1,
                               override.aes = list(shape = 15,
                                                   size = 4))) +
	scale_y_continuous(expand = c(0.01, 0),
                       breaks = seq(0, 100, by=10)) +
	ggrepel::geom_text_repel(data = top_spc_health_highest %>% 
                             	inner_join(spc_health_index, by="spc_common"),
                             aes(label = paste("HI: ", round(health_index, digits=2),
                                               ", Good: ", label_percent(
                                                   accuracy=0.01)(proportion), sep=""),
                                 x = spc_common,
                                 y = ifelse(proportion==1, 100*proportion-21.5,
                                            100*proportion-22)),
                             size=2.2, color="white", hjust=1)

#spc_health_index
#summary(lm(spc_health_index$abundance~spc_health_index$health_index))
#shapiro.test(lm(spc_health_index$abundance~spc_health_index$health_index)$residuals)
#abd_hi_corr <- cor(spc_health_index$abundance, spc_health_index$health_index, method="kendall")
#abd_hi_corr

Paving stones as well as other trunk and branch problems also affect major tree parts (root, trunk, and branch) the most at a species level, similar to what is observed in the analysis of tree population.

Figs. 11 to 13 show the top 25 species with the highest percentage of their trees having at least one problem for each tree part.

# For root problems' graph
spc_root_problems <- trees %>%
	select(spc_common, root_stone:root_other) %>%
	filter(spc_common != "null",
           if_all(-spc_common, ~ .x != "null")) %>%
	mutate(across(root_stone:root_other, ~ ifelse(.x == "Yes", 1, 0)),
           None = ifelse(root_stone == 0 &
                         root_grate == 0 &
                         root_other == 0, 1, 0)) %>%
	group_by(spc_common) %>%
	summarize(none = 100*sum(None)/n(),
              root_stone = 100*sum(root_stone)/n(),
              root_grate = 100*sum(root_grate)/n(),
              root_other = 100*sum(root_other)/n()) %>%
	rename(`Common name of the species` = spc_common,
           `''Paving stones` = root_stone,
           `'Metal grates` = root_grate,
           `Others` = root_other) %>% 
	ungroup() %>%
	filter(rank((none)) <= 25) %>%
	arrange((none)) %>%
    mutate_if(is.numeric, ~(round(., digits = 2))) %>%
	pivot_longer(cols = c(3:5), 
                 names_to = "Root problem",
                 values_to = "% of trees")
spc_root_problems
A tibble: 69 × 4
Common name of the speciesnoneRoot problem% of trees
<chr><dbl><chr><dbl>
White pine 0.00''Paving stones100.00
White pine 0.00'Metal grates 0.00
White pine 0.00Others 0.00
European beech16.67''Paving stones 50.00
European beech16.67'Metal grates 0.00
European beech16.67Others 50.00
Tartar maple16.67''Paving stones 66.67
Tartar maple16.67'Metal grates 0.00
Tartar maple16.67Others 16.67
Southern magnolia26.32''Paving stones 57.89
Southern magnolia26.32'Metal grates 0.00
Southern magnolia26.32Others 21.05
Norway spruce33.33''Paving stones 0.00
Norway spruce33.33'Metal grates 0.00
Norway spruce33.33Others 66.67
Katsura tree42.11''Paving stones 28.95
Katsura tree42.11'Metal grates 21.05
Katsura tree42.11Others 7.89
Tree of heaven45.19''Paving stones 43.27
Tree of heaven45.19'Metal grates 1.92
Tree of heaven45.19Others 12.50
Sassafras47.06''Paving stones 35.29
Sassafras47.06'Metal grates 0.00
Sassafras47.06Others 23.53
Boxelder50.00''Paving stones 50.00
Boxelder50.00'Metal grates 0.00
Boxelder50.00Others 0.00
Cucumber magnolia50.00''Paving stones 16.67
Cucumber magnolia50.00'Metal grates 33.33
Cucumber magnolia50.00Others 33.33
Ohio buckeye58.33''Paving stones29.17
Ohio buckeye58.33'Metal grates 0.00
Ohio buckeye58.33Others12.50
Empress tree58.82''Paving stones41.18
Empress tree58.82'Metal grates 0.00
Empress tree58.82Others 0.00
Cornelian cherry59.26''Paving stones 3.70
Cornelian cherry59.26'Metal grates33.33
Cornelian cherry59.26Others 3.70
Crepe myrtle60.00''Paving stones40.00
Crepe myrtle60.00'Metal grates 0.00
Crepe myrtle60.00Others 0.00
Eastern cottonwood60.00''Paving stones30.00
Eastern cottonwood60.00'Metal grates 0.00
Eastern cottonwood60.00Others20.00
Black walnut60.61''Paving stones39.39
Black walnut60.61'Metal grates 3.03
Black walnut60.61Others 0.00
Japanese tree lilac62.02''Paving stones22.48
Japanese tree lilac62.02'Metal grates 8.53
Japanese tree lilac62.02Others10.85
Honeylocust62.15''Paving stones25.50
Honeylocust62.15'Metal grates 6.28
Honeylocust62.15Others10.66
Japanese hornbeam64.52''Paving stones25.81
Japanese hornbeam64.52'Metal grates 3.23
Japanese hornbeam64.52Others 9.68
Green ash65.45''Paving stones26.88
Green ash65.45'Metal grates 1.04
Green ash65.45Others 8.83
# For trunk problems' graph
spc_trunk_problems <- trees %>%
	select(spc_common, trunk_wire:trnk_other) %>%
	filter(spc_common != "null",
           if_all(-spc_common, ~ .x != "null")) %>%
	mutate(across(trunk_wire:trnk_other, ~ ifelse(.x == "Yes", 1, 0)),
           None = ifelse(trunk_wire == 0 &
                         trnk_light == 0 &
                         trnk_other == 0, 1, 0)) %>%
	group_by(spc_common) %>%
	summarize(none = 100*sum(None)/n(),
              trunk_wire = 100*sum(trunk_wire)/n(),
              trnk_light = 100*sum(trnk_light)/n(),
              trnk_other = 100*sum(trnk_other)/n()) %>%
	rename(`Common name of the species` = spc_common,
           `''Wires or rope` = trunk_wire,
           `'Lighting installed` = trnk_light,
           `Others` = trnk_other) %>% 
	ungroup() %>%
	filter(rank((none)) <= 25) %>%
	arrange((none)) %>%
    mutate_if(is.numeric, ~(round(., digits = 2))) %>%
	pivot_longer(cols = c(3:5), 
                 names_to = "Trunk problem",
                 values_to = "% of trees")
spc_trunk_problems
A tibble: 75 × 4
Common name of the speciesnoneTrunk problem% of trees
<chr><dbl><chr><dbl>
Tartar maple41.67''Wires or rope 0.00
Tartar maple41.67'Lighting installed 0.00
Tartar maple41.67Others58.33
Oklahoma redbud44.44''Wires or rope11.11
Oklahoma redbud44.44'Lighting installed 0.00
Oklahoma redbud44.44Others44.44
Horse chestnut63.64''Wires or rope18.18
Horse chestnut63.64'Lighting installed 0.00
Horse chestnut63.64Others18.18
Cockspur hawthorn66.67''Wires or rope33.33
Cockspur hawthorn66.67'Lighting installed 0.00
Cockspur hawthorn66.67Others 0.00
Crimson king maple66.67''Wires or rope 0.00
Crimson king maple66.67'Lighting installed 0.00
Crimson king maple66.67Others33.33
Paperbark maple66.67''Wires or rope 0.00
Paperbark maple66.67'Lighting installed 0.00
Paperbark maple66.67Others33.33
Hedge maple69.57''Wires or rope 4.35
Hedge maple69.57'Lighting installed 0.00
Hedge maple69.57Others26.09
Japanese snowbell73.33''Wires or rope 0.00
Japanese snowbell73.33'Lighting installed 0.00
Japanese snowbell73.33Others26.67
Pond cypress75.00''Wires or rope 0.00
Pond cypress75.00'Lighting installed 0.00
Pond cypress75.00Others25.00
Silver maple77.46''Wires or rope 8.45
Silver maple77.46'Lighting installed 0.00
Silver maple77.46Others14.08
Tulip-poplar82.35''Wires or rope 0.00
Tulip-poplar82.35'Lighting installed 0.00
Tulip-poplar82.35Others17.65
Paper birch82.98''Wires or rope 2.13
Paper birch82.98'Lighting installed 0.00
Paper birch82.98Others14.89
European beech83.33''Wires or rope 0.00
European beech83.33'Lighting installed 0.00
European beech83.33Others16.67
Mimosa83.33''Wires or rope16.67
Mimosa83.33'Lighting installed 0.00
Mimosa83.33Others 0.00
Green ash84.16''Wires or rope 3.77
Green ash84.16'Lighting installed 0.39
Green ash84.16Others12.21
Dawn redwood84.92''Wires or rope 2.01
Dawn redwood84.92'Lighting installed 0.00
Dawn redwood84.92Others13.57
Japanese hornbeam85.48''Wires or rope 4.84
Japanese hornbeam85.48'Lighting installed 1.61
Japanese hornbeam85.48Others 8.06
Eastern hemlock85.71''Wires or rope 0.00
Eastern hemlock85.71'Lighting installed 0.00
Eastern hemlock85.71Others14.29
Southern red oak85.71''Wires or rope 0.00
Southern red oak85.71'Lighting installed 0.00
Southern red oak85.71Others14.29
Sweetgum86.78''Wires or rope 2.64
Sweetgum86.78'Lighting installed 0.44
Sweetgum86.78Others10.13
# For branch problems' graph
brch_trunk_problems <- trees %>%
	select(spc_common, brch_light:brch_other) %>%
	filter(spc_common != "null",
           if_all(-spc_common, ~ .x != "null")) %>%
	mutate(across(brch_light:brch_other, ~ ifelse(.x == "Yes", 1, 0)),
           None = ifelse(brch_light == 0 &
                         brch_shoe == 0 &
                         brch_other == 0, 1, 0)) %>%
	group_by(spc_common) %>%
	summarize(none = 100*sum(None)/n(),
              brch_light = 100*sum(brch_light)/n(),
              brch_shoe = 100*sum(brch_shoe)/n(),
              brch_other = 100*sum(brch_other)/n()) %>%
	rename(`Common name of the species` = spc_common,
           `''Lights or wires ` = brch_light,
           `'Shoes` = brch_shoe,
           `Others` = brch_other) %>% 
	ungroup() %>%
	filter(rank((none)) <= 25) %>%
	arrange((none)) %>%
    mutate_if(is.numeric, ~(round(., digits = 2))) %>%
	pivot_longer(cols = c(3:5), 
                 names_to = "Branch problem",
                 values_to = "% of trees")
brch_trunk_problems
A tibble: 75 × 4
Common name of the speciesnoneBranch problem% of trees
<chr><dbl><chr><dbl>
Boxelder50.00''Lights or wires 0.00
Boxelder50.00'Shoes 0.00
Boxelder50.00Others50.00
Crimson king maple50.00''Lights or wires 0.00
Crimson king maple50.00'Shoes 0.00
Crimson king maple50.00Others50.00
European alder50.00''Lights or wires 0.00
European alder50.00'Shoes 0.00
European alder50.00Others50.00
Tartar maple50.00''Lights or wires 8.33
Tartar maple50.00'Shoes 0.00
Tartar maple50.00Others50.00
Maple67.57''Lights or wires10.81
Maple67.57'Shoes 0.00
Maple67.57Others21.62
Southern magnolia68.42''Lights or wires 0.00
Southern magnolia68.42'Shoes 0.00
Southern magnolia68.42Others31.58
Sassafras70.59''Lights or wires 5.88
Sassafras70.59'Shoes 0.00
Sassafras70.59Others29.41
Turkish hazelnut70.59''Lights or wires 0.00
Turkish hazelnut70.59'Shoes 0.00
Turkish hazelnut70.59Others29.41
American beech72.73''Lights or wires 4.55
American beech72.73'Shoes 0.00
American beech72.73Others22.73
Paperbark maple73.33''Lights or wires 0.00
Paperbark maple73.33'Shoes 0.00
Paperbark maple73.33Others26.67
Arborvitae80.00''Lights or wires 0.00
Arborvitae80.00'Shoes 0.00
Arborvitae80.00Others20.00
Crepe myrtle80.00''Lights or wires 0.00
Crepe myrtle80.00'Shoes 0.00
Crepe myrtle80.00Others20.00
Eastern cottonwood80.00''Lights or wires 0.00
Eastern cottonwood80.00'Shoes 0.00
Eastern cottonwood80.00Others20.00
Silver birch80.00''Lights or wires20.00
Silver birch80.00'Shoes 0.00
Silver birch80.00Others 0.00
Sugar maple81.25''Lights or wires 2.08
Sugar maple81.25'Shoes 0.00
Sugar maple81.25Others16.67
Cornelian cherry81.48''Lights or wires 3.70
Cornelian cherry81.48'Shoes 0.00
Cornelian cherry81.48Others14.81
Horse chestnut81.82''Lights or wires 0.00
Horse chestnut81.82'Shoes 0.00
Horse chestnut81.82Others18.18
Amur maple83.33''Lights or wires 0.00
Amur maple83.33'Shoes 0.00
Amur maple83.33Others16.67
European beech83.33''Lights or wires 0.00
European beech83.33'Shoes 0.00
European beech83.33Others16.67
Callery pear83.92''Lights or wires 2.32
Callery pear83.92'Shoes 0.11
Callery pear83.92Others14.13

Ranking

As suggested by the urban design team, tree size and health are used to determine which species have the most desirable characteristics. The two metrics used are health index $(HI)$ and median trunk diameter at breast height $(DBH)$ of $54$ inches, respectively.

With that, it is confirmed through a correlation analysis that they have a high to very high positive correlation. This means that an increase in median trunk diameter is associated to an increase in the health index of a species. Below are the results of the correlation tests using three methods:

spearman_corr <- data.frame(
    test_stat=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh,
         method = "spearman", exact = FALSE)$statistic,
    corr_coeff=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh,
         method = "spearman", exact = FALSE)$estimate,
    p_value=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh,
         method = "spearman", exact = FALSE)$p.value)

kendall_corr <- data.frame(
    test_stat=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh,
         method = "kendall", exact = FALSE)$statistic,
    corr_coeff=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh,
         method = "kendall", exact = FALSE)$estimate,
    p_value=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh,
         method = "kendall", exact = FALSE)$p.value)

pearson_corr <- data.frame(
    test_stat=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh)$statistic,
    corr_coeff=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh)$estimate,
    p_value=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh)$p.value)

corr_coeffs <- spearman_corr %>%
    mutate(method = "Spearman") %>%
	bind_rows(kendall_corr %>%
              	mutate(method = "Kendall"), 
              pearson_corr %>%
                mutate(method = "Pearson")) %>%
	select(method, everything()) %>%
	mutate(p_value = formatC(p_value, format = "e", digits = 4))

rownames(corr_coeffs) <- 1:nrow(corr_coeffs)

# HTML Table for correlation results
#kable(corr_coeffs, 
#      caption = " ",#
#      label = "tables", format = "html", booktabs = TRUE)
corr_coeffs %>%
	mutate_if(is.numeric, list(~round(., digits=4))) %>%
	mutate_if(is.numeric, list(~prettyNum(., big.mark=",")))
A data.frame: 3 × 4
methodtest_statcorr_coeffp_value
<chr><chr><chr><chr>
1Spearman4,759.5010.98641.2123e-100
2Kendall14.78120.93611.9379e-49
3Pearson15.46710.80936.6475e-31

To determine species ranking, the sum of ranks for health index and median trunk diameter was computed to quantify each species’ overall rank relative to others.

Additionally, two ranking systems were produced. The first encompassed all $128$ species. The second, however, adjusted for abundance by including only species with tree counts of at least $29$, representing the median species abundance.

Figures 14 and 15 provide dashboard snapshots illustrating the results from both ranking systems.

# spc_first_ranking <- spc_health_index %>%
# 	select(spc_common, abundance, health_index) %>%
# 	inner_join(trees %>% 
#                group_by(spc_common) %>%
#                filter(spc_common != "null", health != "null") %>%
#                summarize(abundance = n(),
#                          median_tree_dbh = median(tree_dbh)),
#     	by=c("spc_common", "abundance")) %>%
# 	mutate(dbh_rank = percent_rank(median_tree_dbh),
# 		   hi_rank = percent_rank(health_index),
# 		   ps = (dbh_rank+hi_rank)/2) %>%
# 	arrange(desc(ps))

# spc_first_ranking

spc_first_ranking <- spc_health_index %>%
	select(spc_common, abundance, health_index) %>%
	inner_join(trees %>% 
               group_by(spc_common) %>%
               filter(spc_common != "null", health != "null") %>%
               summarize(abundance = n(),
                         median_tree_dbh = median(tree_dbh)),
    	by=c("spc_common", "abundance")) %>%
	mutate(abd_rank = rank(desc(abundance)),
		   hi_rank = rank(desc(health_index)),
		   dbh_rank = rank(desc(median_tree_dbh)),
		   rank_sum = (hi_rank + dbh_rank)/2) %>%
	arrange(rank_sum)

spc_second_ranking <- spc_health_index %>%
	select(spc_common, abundance, health_index) %>%
	inner_join(trees %>% 
               group_by(spc_common) %>%
               filter(spc_common != "null", health != "null") %>%
               summarize(abundance = n(),
                         median_tree_dbh = median(tree_dbh)),
    	by=c("spc_common", "abundance")) %>%
# Filter out species with abundances less than the median abundances
	filter(abundance >= median(spc_tree_dbh_stats$abundance)
          ) %>% 
mutate(abd_rank = rank(desc(abundance)),
       hi_rank = rank(desc(health_index)),
          dbh_rank = rank(desc(median_tree_dbh)),
       rank_sum = (hi_rank + dbh_rank)) %>%
	arrange(rank_sum)

## Top species by rank sums (health index and median tree dbh)

#spc_first_ranking %>%
#select(spc_common, abundance, rank_sum, everything())

#spc_second_ranking %>%
#select(spc_common, abundance, #rank_sum, everything())

# For graphs
spc_first_ranking_long <- spc_first_ranking %>%
	rename(`Common name of the species` = spc_common,
           `Health index` = health_index,
           `Median trunk dbh` = median_tree_dbh) %>%
	pivot_longer(cols = c(3:4), 
                 names_to = "Measurement",
                 values_to = "Value")

spc_second_ranking_long <- spc_second_ranking %>%
	rename(`Common name of the species` = spc_common,
           `Health index` = health_index,
           `Median trunk dbh` = median_tree_dbh) %>%
	pivot_longer(cols = c(3:4), 
                 names_to = "Measurement",
                 values_to = "Value")


#spc_second_ranking_long$`Common name of the species` <- factor(
#    spc_second_ranking_long$`Common name of the species`,
#	levels = (spc_second_ranking)$spc_common,
    #ordered = TRUE
#)

# Tree size and Health 
top_spc_first_ranking <- spc_first_ranking_long %>%
	arrange(rank_sum) %>%
	filter(`Common name of the species` %in% (spc_first_ranking %>% slice(1:10))$spc_common)

top_spc_second_ranking <- spc_second_ranking_long %>%
	arrange(rank_sum) %>%
	filter(`Common name of the species` %in% (spc_second_ranking %>% slice(1:10))$spc_common)


# Tree size
top_dbh_spc <- spc_second_ranking_long %>%
	arrange(desc(Measurement)) %>%
	filter(Measurement == "Median trunk dbh",
           `Common name of the species` %in% (spc_second_ranking %>% slice(1:10))$spc_common)

# Health
top_hi_spc <- spc_second_ranking_long %>%
	arrange(desc(Measurement)) %>%
	rename(`Health index` = Value) %>%
	filter(`Measurement` == "Health index",
           `Common name of the species` %in% (spc_second_ranking %>% slice(1:10))$spc_common) 

spc_first_ranking_long %>%
	select(-(abd_rank))
A tibble: 256 × 7
Common name of the speciesabundancehi_rankdbh_rankrank_sumMeasurementValue
<chr><int><dbl><dbl><dbl><chr><dbl>
Smoketree 1 6.5 8.0 7.25Health index 1.0000000
Smoketree 1 6.5 8.0 7.25Median trunk dbh11.0000000
Black maple 1013.0 8.010.50Health index 0.9666667
Black maple 1013.0 8.010.50Median trunk dbh11.0000000
Amur cork tree 814.0 8.011.00Health index 0.9583333
Amur cork tree 814.0 8.011.00Median trunk dbh11.0000000
Siberian elm 15623.0 8.015.50Health index 0.9316239
Siberian elm 15623.0 8.015.50Median trunk dbh11.0000000
Pitch pine 5 6.526.516.50Health index 1.0000000
Pitch pine 5 6.526.516.50Median trunk dbh 8.0000000
Red horse chestnut 1 6.526.516.50Health index 1.0000000
Red horse chestnut 1 6.526.516.50Median trunk dbh 8.0000000
Willow oak 88921.013.017.00Health index 0.9366329
Willow oak 88921.013.017.00Median trunk dbh10.0000000
Honeylocust1317520.019.519.75Health index 0.9387223
Honeylocust1317520.019.519.75Median trunk dbh 9.0000000
American elm 169836.0 4.020.00Health index 0.9185316
American elm 169836.0 4.020.00Median trunk dbh12.0000000
Pin oak 458427.019.523.25Health index 0.9282286
Pin oak 458427.019.523.25Median trunk dbh 9.0000000
Tree of heaven 10439.0 8.023.50Health index 0.9134615
Tree of heaven 10439.0 8.023.50Median trunk dbh11.0000000
White ash 5033.015.024.00Health index 0.9200000
White ash 5033.015.024.00Median trunk dbh 9.5000000
Black locust 25937.013.025.00Health index 0.9176319
Black locust 25937.013.025.00Median trunk dbh10.0000000
Black walnut 3334.019.526.75Health index 0.9191919
Black walnut 3334.019.526.75Median trunk dbh 9.0000000
Sophora 445335.019.527.25Health index 0.9187813
Sophora 445335.019.527.25Median trunk dbh 9.0000000
Turkish hazelnut 17103.5 87.0 95.25Health index0.7843137
Turkish hazelnut 17103.5 87.0 95.25Median trunk dbh4.0000000
Tulip-poplar 34112.0 87.0 99.50Health index0.7647059
Tulip-poplar 34112.0 87.0 99.50Median trunk dbh4.0000000
Common hackberry170 87.0113.0100.00Health index0.8352941
Common hackberry170 87.0113.0100.00Median trunk dbh3.0000000
Maple 37117.0 87.0102.00Health index0.7027027
Maple 37117.0 87.0102.00Median trunk dbh4.0000000
Himalayan cedar 6 90.0125.5107.75Health index0.8333333
Himalayan cedar 6 90.0125.5107.75Median trunk dbh2.0000000
Sassafras 17103.5113.0108.25Health index0.7843137
Sassafras 17103.5113.0108.25Median trunk dbh3.0000000
Kentucky yellowwood 18109.0113.0111.00Health index0.7777778
Kentucky yellowwood 18109.0113.0111.00Median trunk dbh3.0000000
Norway spruce 3109.0113.0111.00Health index0.7777778
Norway spruce 3109.0113.0111.00Median trunk dbh3.0000000
Horse chestnut 11114.0113.0113.50Health index0.7575758
Horse chestnut 11114.0113.0113.50Median trunk dbh3.0000000
Pagoda dogwood 18115.0113.0114.00Health index0.7407407
Pagoda dogwood 18115.0113.0114.00Median trunk dbh3.0000000
Paperbark maple 15120.5113.0116.75Health index0.6666667
Paperbark maple 15120.5113.0116.75Median trunk dbh3.0000000
Spruce 1120.5113.0116.75Health index0.6666667
Spruce 1120.5113.0116.75Median trunk dbh3.0000000
Eastern hemlock 7126.0113.0119.50Health index0.5238095
Eastern hemlock 7126.0113.0119.50Median trunk dbh3.0000000
Douglas-fir 2120.5125.5123.00Health index0.6666667
Douglas-fir 2120.5125.5123.00Median trunk dbh2.0000000
Pond cypress 12124.5122.0123.25Health index0.5555556
Pond cypress 12124.5122.0123.25Median trunk dbh2.5000000

Fig. 14: Dashboard Results Using ‘Rank All Species, by Size & Health’ System </br> </br> Fig. 15: Dashboard Results Using ‘Rank Species with Abundance ≥ 29, by Size & Health’

Recommendations

The following are some potential courses of action for Manhattan’s urban planning department:

  • Large southern neighborhoods such as Midtown-Midtown South (MN17), SoHo-TriBeCa-Civic Center-Little Italy (MN24), and Lower East Side (MN28), which are ranked third, sixth, and eighth in terms of land area, respectively, but only ranked $25$th, $15$th, and $19$th in terms of tree counts, can be ideal locations for planting trees.

  • Some of the issues that need to be prioritized in the Stuyvesant Town-Cooper Village neighborhood include low tree counts, species richness, and a high number of trees that are offset from curb.

  • Although two rankings were produced, the second one has a better rank estimation due to large sample size per species; thus, the top five species (out of the 64 included) in terms of size and health that are recommended to be planted on the streets of Manhattan are:

    1. Siberian elm
      • Abundance: $156$
      • Median trunk diameter: $11$ $(3$rd$)$
      • Heath index: $0.9316$ $(6$th$)$
    2. Willow oak
      • Abundance: $889$
      • Median trunk diameter: $10$ $(6$th$)$
      • Heath index: $0.9366$ $(5$th$)$
    3. Honeylocust
      • Abundance: $13,176$
      • Median trunk diameter: $9$ $(12$th$)$
      • Heath index: $0.9387$ $(4$th$)$
    4. American elm
      • Abundance: $1,698$
      • Median trunk diameter: $12$ $(2$nd$)$
      • Heath index: $0.9185$ $(17$th$)$
    5. Pin oak
      • Abundance: $4,584$
      • Median trunk diameter: $9$ $(12$th$)$
      • Heath index: $0.9282$ $(9$th$)$

    </br>

  • Trees of species Smoketree, Black maple, Amur cork tree, Pitch pine, and Red horse chestnut from the first ranking can also be considered as they have shown superior sizes and health. However, it is also suggested looking into related literature and/or more adequate data about them.

Appendix

Tables & Figures

Shape area per neighborhood

neighborhoods %>%
	filter(boroname == "Manhattan", ntacode != "MN99") %>%
	arrange(desc(shape_area)) %>%
	st_drop_geometry() %>%
	select(-boroname)
A data.frame: 28 × 3
ntacodentanameshape_area
<chr><chr><dbl>
1MN13Hudson Yards-Chelsea-Flatiron-Union Square37029727
2MN12Upper West Side34381053
3MN17Midtown-Midtown South30192057
4MN03Central Harlem North-Polo Grounds25403425
5MN23West Village25000526
6MN24SoHo-TriBeCa-Civic Center-Little Italy24859569
7MN34East Harlem North24495420
8MN28Lower East Side23297616
9MN36Washington Heights South23100223
10MN35Washington Heights North22662313
11MN31Lenox Hill-Roosevelt Island21501565
12MN09Morningside Heights20158317
13MN40Upper East Side-Carnegie Hill20065329
14MN25Battery Park City-Lower Manhattan19056256
15MN15Clinton18381380
16MN01Marble Hill-Inwood17725321
17MN19Turtle Bay-East Midtown17397872
18MN33East Harlem South16650738
19MN04Hamilton Heights16093788
20MN14Lincoln Square15805668
21MN27Chinatown14501953
22MN20Murray Hill-Kips Bay14465848
23MN11Central Harlem South14436192
24MN32Yorkville13594780
25MN22East Village10895491
26MN06Manhattanville10647078
27MN21Gramercy 7531455
28MN50Stuyvesant Town-Cooper Village 5575232

Tree count per neighborhood

# Tree count per neighborhood
nbh_tree_cnts %>%
	mutate(Percentage = label_percent(accuracy=0.01)(proportion)) %>%
	select(-proportion)
A tibble: 28 × 4
ntanta_namenumber_of_treesPercentage
<chr><chr><int><chr>
MN12Upper West Side58079.04%
MN40Upper East Side-Carnegie Hill46167.19%
MN23West Village38015.92%
MN03Central Harlem North-Polo Grounds34695.40%
MN13Hudson Yards-Chelsea-Flatiron-Union Square29314.56%
MN36Washington Heights South29244.55%
MN09Morningside Heights27044.21%
MN11Central Harlem South26434.11%
MN35Washington Heights North26124.07%
MN34East Harlem North25053.90%
MN04Hamilton Heights23633.68%
MN31Lenox Hill-Roosevelt Island22773.55%
MN19Turtle Bay-East Midtown22263.47%
MN32Yorkville21803.39%
MN24SoHo-TriBeCa-Civic Center-Little Italy21703.38%
MN14Lincoln Square20443.18%
MN15Clinton19543.04%
MN33East Harlem South19453.03%
MN28Lower East Side19162.98%
MN20Murray Hill-Kips Bay17042.65%
MN22East Village15422.40%
MN01Marble Hill-Inwood14762.30%
MN27Chinatown14572.27%
MN25Battery Park City-Lower Manhattan12942.01%
MN17Midtown-Midtown South11841.84%
MN21Gramercy11421.78%
MN06Manhattanville 9021.40%
MN50Stuyvesant Town-Cooper Village 4410.69%

Tree count per curb location

number_of_trees_per_curb_loc
A tibble: 2 × 3
curb_locnumber_of_treespercentage
<chr><int><chr>
OnCurb5993293.07%
OffsetFromCurb 42976.67%

Curb location per neighborhood

# Curb location per neighborhood
curb_loc_per_nbh %>%
	arrange(desc(curb_loc), desc(proportion)) %>%
	select(-proportion)
A tibble: 56 × 5
ntanta_namecurb_locnumber_of_treespercentage
<chr><ord><chr><int><chr>
MN22East VillageOnCurb153399.42%
MN06ManhattanvilleOnCurb 89098.67%
MN21GramercyOnCurb111997.99%
MN23West VillageOnCurb372197.90%
MN13Hudson Yards-Chelsea-Flatiron-Union SquareOnCurb286097.58%
MN32YorkvilleOnCurb212797.57%
MN15ClintonOnCurb190697.54%
MN35Washington Heights NorthOnCurb252896.78%
MN31Lenox Hill-Roosevelt IslandOnCurb219896.53%
MN34East Harlem NorthOnCurb241096.21%
MN36Washington Heights SouthOnCurb280595.93%
MN03Central Harlem North-Polo GroundsOnCurb332495.82%
MN20Murray Hill-Kips BayOnCurb163095.66%
MN11Central Harlem SouthOnCurb252395.46%
MN01Marble Hill-InwoodOnCurb140895.39%
MN04Hamilton HeightsOnCurb224695.05%
MN19Turtle Bay-East MidtownOnCurb211595.01%
MN17Midtown-Midtown SouthOnCurb110493.24%
MN40Upper East Side-Carnegie HillOnCurb430193.18%
MN14Lincoln SquareOnCurb185190.56%
MN12Upper West SideOnCurb522589.98%
MN24SoHo-TriBeCa-Civic Center-Little ItalyOnCurb195089.86%
MN28Lower East SideOnCurb171489.46%
MN33East Harlem SouthOnCurb172588.69%
MN09Morningside HeightsOnCurb229384.80%
MN27ChinatownOnCurb121883.60%
MN25Battery Park City-Lower ManhattanOnCurb100977.98%
MN50Stuyvesant Town-Cooper VillageOnCurb 19945.12%
MN50Stuyvesant Town-Cooper VillageOffsetFromCurb 24254.88%
MN25Battery Park City-Lower ManhattanOffsetFromCurb 28522.02%
MN27ChinatownOffsetFromCurb 23916.40%
MN09Morningside HeightsOffsetFromCurb 41115.20%
MN33East Harlem SouthOffsetFromCurb 22011.31%
MN28Lower East SideOffsetFromCurb 20210.54%
MN24SoHo-TriBeCa-Civic Center-Little ItalyOffsetFromCurb 22010.14%
MN12Upper West SideOffsetFromCurb 58210.02%
MN14Lincoln SquareOffsetFromCurb 1939.44%
MN40Upper East Side-Carnegie HillOffsetFromCurb 3156.82%
MN17Midtown-Midtown SouthOffsetFromCurb 806.76%
MN19Turtle Bay-East MidtownOffsetFromCurb 1114.99%
MN04Hamilton HeightsOffsetFromCurb 1174.95%
MN01Marble Hill-InwoodOffsetFromCurb 684.61%
MN11Central Harlem SouthOffsetFromCurb 1204.54%
MN20Murray Hill-Kips BayOffsetFromCurb 744.34%
MN03Central Harlem North-Polo GroundsOffsetFromCurb 1454.18%
MN36Washington Heights SouthOffsetFromCurb 1194.07%
MN34East Harlem NorthOffsetFromCurb 953.79%
MN31Lenox Hill-Roosevelt IslandOffsetFromCurb 793.47%
MN35Washington Heights NorthOffsetFromCurb 843.22%
MN15ClintonOffsetFromCurb 482.46%
MN32YorkvilleOffsetFromCurb 532.43%
MN13Hudson Yards-Chelsea-Flatiron-Union SquareOffsetFromCurb 712.42%
MN23West VillageOffsetFromCurb 802.10%
MN21GramercyOffsetFromCurb 232.01%
MN06ManhattanvilleOffsetFromCurb 121.33%
MN22East VillageOffsetFromCurb 90.58%
# Tree population's attributes
pop_attributes %>%
	select(-proportion)
A data.frame: 23 × 4
attributecategorynumber_of_treespercentage
<ord><ord><int><chr>
statusAlive6242797.19%
statusDead 18022.81%
healthGood4735875.86%
healthFair1146018.36%
healthPoor 36095.78%
root_stoneNo5165380.42%
root_stoneYes1257619.58%
root_grateNo6174796.14%
root_grateYes 24823.86%
root_otherNo5921292.19%
root_otherYes 50177.81%
trunk_wireNo6331298.57%
trunk_wireYes 9171.43%
trnk_lightNo6389899.48%
trnk_lightYes 3310.52%
trnk_otherNo5864991.31%
trnk_otherYes 55808.69%
brch_lightNo6335498.64%
brch_lightYes 8751.36%
brch_shoeNo6416899.91%
brch_shoeYes 610.09%
brch_otherNo5766589.78%
brch_otherYes 656410.22%

Richness (number of tree species) per neighborhood

nbh_rchns
A tibble: 28 × 3
ntanta_namerichness
<chr><chr><int>
MN35Washington Heights North81
MN28Lower East Side78
MN36Washington Heights South77
MN23West Village76
MN03Central Harlem North-Polo Grounds75
MN04Hamilton Heights73
MN12Upper West Side73
MN40Upper East Side-Carnegie Hill73
MN11Central Harlem South71
MN22East Village68
MN09Morningside Heights66
MN34East Harlem North64
MN24SoHo-TriBeCa-Civic Center-Little Italy62
MN01Marble Hill-Inwood60
MN19Turtle Bay-East Midtown60
MN27Chinatown58
MN32Yorkville57
MN31Lenox Hill-Roosevelt Island55
MN14Lincoln Square54
MN20Murray Hill-Kips Bay53
MN06Manhattanville52
MN15Clinton52
MN33East Harlem South46
MN13Hudson Yards-Chelsea-Flatiron-Union Square44
MN21Gramercy39
MN25Battery Park City-Lower Manhattan39
MN17Midtown-Midtown South37
MN50Stuyvesant Town-Cooper Village21

Species abundances

Summary statistics of species abundances (number of trees per species)

defaultW <- getOption("warn")
options(warn=-1)

tree_attributes <- trees %>%
	select(spc_common, tree_dbh:brch_other) %>%
	filter(!is.na(spc_common))

spc_common <- levels(factor(tree_attributes$spc_common))

tree_attributes$spc_common <- factor(tree_attributes$spc_common,
                               levels = spc_common)

# Identified species abundances
identified_spc_abd <- trees %>%
	filter(!is.na(spc_common)) %>%
	group_by(spc_common) %>%
	summarize(abundance = n())

# Summary statistics of species abundances
spc_abd_stats <- data.frame(number_of_identified_spc = length(identified_spc_abd$abundance),
    						mean = mean(identified_spc_abd$abundance),
                            sd = sd(identified_spc_abd$abundance),
                            min = min(identified_spc_abd$abundance),
                            first_quartile = quantile(identified_spc_abd$abundance, probs = 0.25),
                            median = median(identified_spc_abd$abundance),
                            third_quartile = quantile(identified_spc_abd$abundance, probs = 0.75),
                            max = max(identified_spc_abd$abundance))
row.names(spc_abd_stats) <- "spc_abundance" 

# HTML Table for Number of Trees per Species
#kable(tree_dbh_stats %>%
#	  	mutate_if(is.numeric, list(~format(round(., 4), nsmall = 4))),
#     "html", caption = "Table _: Summary statistics of the tree diameter")

# Histogram with density curve of the species abundances
tree_count_per_species_dist_plot <- ggplot(identified_spc_abd,
                                           aes(x = abundance)) + 
	geom_histogram(aes(y = after_stat(density)),
                   binwidth=25,
                   color=1,
                   fill="#5FBD5F") + geom_density(linewidth=0.85,
                                                  linetype=1,
                                                  colour = muted("5FBD5F"),
                                                  alpha=0.5) +

# Plot mean and median
	geom_vline(aes(xintercept = mean(abundance)), col="red", size=0.6) +
	geom_vline(aes(xintercept = median(abundance)), col="blue", size=0.6) +

	theme(axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color="#65707C",
                                   size=12,
                                   family="sans serif"),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.subtitle = element_text(color="#65707C",
                                    hjust=-0.33,
                                    size=10,
                                    family="sans serif"),
          plot.title = element_text(color="#65707C",
                                    hjust=0.5,
                                    size=14,
                                    family="sans serif")) +
	ggtitle("\nFig. 16: Distribution of the Species Abundance                \n") +
	labs(x="\nSpecies abundance\n", y="\nDensity\n") +
	scale_x_continuous(expand = c(0.01, 0), 
                       limits = c(0, 2550),
                       breaks = seq(0, 2550, by=250)) +
	scale_y_continuous(expand = c(0.01, 0),
                       limits = c(0, 0.0081), 
                       breaks = seq(0, 0.0081, by=0.001))

spc_abd_stats

options(warn = defaultW)
A data.frame: 1 × 8
number_of_identified_spcmeansdminfirst_quartilemedianthird_quartilemax
<int><dbl><dbl><int><dbl><dbl><dbl><int>
spc_abundance128487.71881597.82818.7528.5167.7513176

Summary statistics of species’ tree DBHs

# Summary statistics of species' tree dbhs
spc_tree_dbh_stats
A tibble: 128 × 9
spc_commonabundancemean_tree_dbhsd_tree_dbhmin_tree_dbhfirst_quartile_tree_dbhmedian_tree_dbhthird_quartile_tree_dbhmax_tree_dbh
<chr><int><dbl><dbl><dbl><dbl><dbl><dbl><dbl>
Weeping willow 1213.5000007.317476 4 8.0014.019.00 26
London planetree 412213.1686077.340801 1 7.0013.018.00 48
White pine 113.000000 NA1313.0013.013.00 13
American elm 169813.8992939.703312 1 6.0012.019.00 62
Amur cork tree 8 9.6250003.925648 3 8.5011.012.25 13
Black maple 1012.6000008.408990 4 5.0011.019.50 26
Ohio buckeye 2411.9583335.368824 3 9.5011.015.25 24
Siberian elm 15612.0641037.545714 2 5.7511.017.00 33
Smoketree 111.000000 NA1111.0011.011.00 11
Sycamore maple 2311.5217396.280341 2 7.5011.016.00 26
Tree of heaven 10411.4519236.584595 2 5.0011.016.00 34
Ash 58 9.6034482.943561 3 8.0010.011.75 16
Black locust 259 9.7683404.735689 2 5.0010.013.00 21
Willow oak 88910.8110249.331016 1 5.0010.014.00199
White ash 50 9.8000004.347178 3 6.00 9.513.00 18
Black walnut 33 9.6363646.004260 2 4.00 9.013.00 26
Eastern cottonwood 1010.8000006.178817 3 7.25 9.011.75 22
Green ash 770 9.2558444.371351 0 6.00 9.012.00 28
Honeylocust13176 9.0580603.997006 0 6.00 9.011.00109
Mulberry 6811.0000007.732467 1 5.00 9.015.00 44
Norway maple 29010.2379315.801379 2 6.00 9.013.00 35
Pin oak 458410.0684997.982340 1 5.00 9.013.00318
Sophora 4453 9.2259154.892435 1 5.00 9.013.00 38
Callery pear 7297 8.6813764.717342 1 6.00 8.011.00228
Catalpa 13 8.5384624.370648 4 6.00 8.0 9.00 21
Ginkgo 5859 8.4459814.159496 1 5.00 8.011.00 74
Pignut hickory 1 8.000000 NA 8 8.00 8.0 8.00 8
Pitch pine 5 7.4000003.286335 4 4.00 8.010.00 11
Red horse chestnut 1 8.000000 NA 8 8.00 8.0 8.00 8
American hophornbeam 84 8.3452384.956422 2 4.00 7.512.00 22
Shingle oak2055.8536594.278084713.004.0 7.0030
Southern red oak 77.1428574.488079434.004.010.5014
Sweetgum2274.9911893.376114923.004.0 6.0022
Tulip-poplar 344.2352940.955330324.004.0 5.00 6
Turkish hazelnut 174.7647062.905370323.004.0 5.0011
White oak2415.2406642.906918123.004.0 7.0017
American beech 225.2272733.841277313.003.5 7.5016
Blackgum 93.5555562.554951622.003.0 4.0010
Chinese fringetree 93.5555561.666666722.003.0 4.00 7
Common hackberry1704.3235292.848445912.003.0 5.0014
Eastern hemlock 73.5714290.786795833.003.0 4.00 5
Eastern redcedar 423.4761902.109653722.003.0 4.0010
Hardy rubber tree 663.8030302.275080422.003.0 5.0014
Horse chestnut 113.0909090.700649023.003.0 3.50 4
Kentucky yellowwood 184.6666673.235828823.003.0 4.0014
Mimosa 123.7500002.598076212.003.0 4.2511
Norway spruce 34.0000002.645751322.503.0 5.00 7
Pagoda dogwood 184.8888894.444281022.253.0 4.0016
Paperbark maple 153.2666671.709915112.003.0 4.00 8
Sassafras 175.4705884.229622423.003.0 6.0016
Spruce 13.000000 NA33.003.0 3.00 3
Swamp white oak6814.0279002.472338103.003.0 4.0032
Blue spruce 44.2500003.862210122.002.5 4.7510
Pond cypress 122.6666670.887625422.002.5 3.00 5
Scots pine 22.5000000.707106822.252.5 2.75 3
Arborvitae 53.4000003.130495222.002.0 2.00 9
Douglas-fir 22.0000001.414213611.502.0 2.50 3
Himalayan cedar 62.3333330.516397822.002.0 2.75 3
Persian ironwood 12.000000 NA22.002.0 2.00 2
Osage-orange 10.000000 NA00.000.0 0.00 0

Status per species

# Status per species
spc_status
A tibble: 129 × 4
spc_commonstatusnumber_of_treespercentage_wrt_spc
<chr><chr><int><chr>
HoneylocustDead 10.01%
HoneylocustAlive1317599.99%
'Schubert' chokecherryAlive 163100.00%
American beechAlive 22100.00%
American elmAlive 1698100.00%
American hophornbeamAlive 84100.00%
American hornbeamAlive 85100.00%
American larchAlive 7100.00%
American lindenAlive 1583100.00%
Amur cork treeAlive 8100.00%
Amur maackiaAlive 59100.00%
Amur mapleAlive 30100.00%
ArborvitaeAlive 5100.00%
AshAlive 58100.00%
Atlantic white cedarAlive 12100.00%
Bald cypressAlive 89100.00%
Bigtooth aspenAlive 5100.00%
Black cherryAlive 32100.00%
Black locustAlive 259100.00%
Black mapleAlive 10100.00%
Black oakAlive 192100.00%
Black pineAlive 3100.00%
Black walnutAlive 33100.00%
BlackgumAlive 9100.00%
Blue spruceAlive 4100.00%
BoxelderAlive 2100.00%
Bur oakAlive 36100.00%
Callery pearAlive 7297100.00%
CatalpaAlive 13100.00%
CherryAlive 869100.00%
Sawtooth oakAlive 353100.00%
Scarlet oakAlive 71100.00%
Schumard's oakAlive 137100.00%
Scots pineAlive 2100.00%
ServiceberryAlive 38100.00%
Shingle oakAlive 205100.00%
Siberian elmAlive 156100.00%
Silver birchAlive 10100.00%
Silver lindenAlive 541100.00%
Silver mapleAlive 71100.00%
SmoketreeAlive 1100.00%
SophoraAlive4453100.00%
Southern magnoliaAlive 19100.00%
Southern red oakAlive 7100.00%
SpruceAlive 1100.00%
Sugar mapleAlive 48100.00%
Swamp white oakAlive 681100.00%
SweetgumAlive 227100.00%
Sycamore mapleAlive 23100.00%
Tartar mapleAlive 12100.00%
Tree of heavenAlive 104100.00%
Tulip-poplarAlive 34100.00%
Turkish hazelnutAlive 17100.00%
Two-winged silverbellAlive 8100.00%
Virginia pineAlive 3100.00%
Weeping willowAlive 12100.00%
White ashAlive 50100.00%
White oakAlive 241100.00%
White pineAlive 1100.00%
Willow oakAlive 889100.00%

Health per species

# Health per species
spc_health %>%
	select(-proportion)
A tibble: 332 × 4
spc_commonhealthnumber_of_treespercentage
<chr><fct><int><chr>
'Schubert' chokecherryGood 11168.10%
'Schubert' chokecherryFair 4024.54%
'Schubert' chokecherryPoor 127.36%
American beechGood 1568.18%
American beechFair 418.18%
American beechPoor 313.64%
American elmGood136180.15%
American elmFair 25915.25%
American elmPoor 784.59%
American hophornbeamGood 6476.19%
American hophornbeamFair 1214.29%
American hophornbeamPoor 89.52%
American hornbeamGood 6778.82%
American hornbeamFair 1315.29%
American hornbeamPoor 55.88%
American larchFair 342.86%
American larchGood 342.86%
American larchPoor 114.29%
American lindenGood102064.43%
American lindenFair 37923.94%
American lindenPoor 18411.62%
Amur cork treeGood 787.50%
Amur cork treeFair 112.50%
Amur maackiaGood 4677.97%
Amur maackiaFair 1016.95%
Amur maackiaPoor 35.08%
Amur mapleGood 1963.33%
Amur mapleFair 723.33%
Amur maplePoor 413.33%
ArborvitaeGood 5100.00%
Sycamore mapleFair 730.43%
Sycamore maplePoor 28.70%
Tartar mapleGood 541.67%
Tartar mapleFair 433.33%
Tartar maplePoor 325.00%
Tree of heavenGood 8278.85%
Tree of heavenFair 1716.35%
Tree of heavenPoor 54.81%
Tulip-poplarGood 1750.00%
Tulip-poplarFair 1029.41%
Tulip-poplarPoor 720.59%
Turkish hazelnutFair 952.94%
Turkish hazelnutGood 741.18%
Turkish hazelnutPoor 15.88%
Two-winged silverbellGood 562.50%
Two-winged silverbellFair 337.50%
Virginia pineGood 266.67%
Virginia pinePoor 133.33%
Weeping willowGood 866.67%
Weeping willowFair 433.33%
White ashGood 4080.00%
White ashFair 816.00%
White ashPoor 24.00%
White oakGood16267.22%
White oakFair 5623.24%
White oakPoor 239.54%
White pineFair 1100.00%
Willow oakGood74784.03%
Willow oakFair11512.94%
Willow oakPoor 273.04%

Health index per species

spc_health_index %>%
	select(-abundance)
A tibble: 128 × 2
spc_commonhealth_index
<chr><dbl>
Arborvitae1.0000000
Black pine1.0000000
Blue spruce1.0000000
Crepe myrtle1.0000000
European beech1.0000000
Osage-orange1.0000000
Persian ironwood1.0000000
Pitch pine1.0000000
Red horse chestnut1.0000000
Red pine1.0000000
Scots pine1.0000000
Smoketree1.0000000
Black maple0.9666667
Amur cork tree0.9583333
Golden raintree0.9554318
Southern red oak0.9523810
Sawtooth oak0.9471199
Kentucky coffeetree0.9415709
Japanese maple0.9393939
Honeylocust0.9387223
Willow oak0.9366329
Holly0.9358974
Siberian elm0.9316239
Southern magnolia0.9298246
Eastern redcedar0.9285714
Hawthorn0.9284627
Pin oak0.9282286
Crab apple0.9260107
Blackgum0.9259259
Shingle oak0.9252033
Bigtooth aspen0.8000000
Eastern cottonwood0.8000000
Japanese snowbell0.8000000
Hedge maple0.7971014
Sassafras0.7843137
Turkish hazelnut0.7843137
Silver maple0.7840376
Katsura tree0.7807018
Cucumber magnolia0.7777778
Kentucky yellowwood0.7777778
Norway spruce0.7777778
Pine0.7777778
Virginia pine0.7777778
Tulip-poplar0.7647059
American larch0.7619048
Horse chestnut0.7575758
Pagoda dogwood0.7407407
Tartar maple0.7222222
Maple0.7027027
Cockspur hawthorn0.6666667
Douglas-fir0.6666667
Paperbark maple0.6666667
Pignut hickory0.6666667
Spruce0.6666667
White pine0.6666667
Crimson king maple0.5555556
Pond cypress0.5555556
Eastern hemlock0.5238095
Boxelder0.5000000
European alder0.5000000

Species’ distribution of root problems

trees %>%
	select(spc_common, root_stone:root_other) %>%
	filter(spc_common != "null",
           if_all(-spc_common, ~ .x != "null")) %>%
	mutate(across(root_stone:root_other, ~ ifelse(.x == "Yes", 1, 0)),
           no_problem = ifelse(root_stone == 0 &
                               root_grate == 0 &
                               root_other == 0, 1, 0)) %>%
	group_by(spc_common) %>%
	summarize(no_problem = 100*sum(no_problem)/n(),
              root_stone = 100*sum(root_stone)/n(),
              root_grate = 100*sum(root_grate)/n(),
              root_other = 100*sum(root_other)/n()) %>%
	arrange(no_problem) %>%
    mutate_if(is.numeric, ~(round(., digits = 2)))
A tibble: 128 × 5
spc_commonno_problemroot_stoneroot_grateroot_other
<chr><dbl><dbl><dbl><dbl>
White pine 0.00100.00 0.00 0.00
European beech16.67 50.00 0.0050.00
Tartar maple16.67 66.67 0.0016.67
Southern magnolia26.32 57.89 0.0021.05
Norway spruce33.33 0.00 0.0066.67
Katsura tree42.11 28.9521.05 7.89
Tree of heaven45.19 43.27 1.9212.50
Sassafras47.06 35.29 0.0023.53
Boxelder50.00 50.00 0.00 0.00
Cucumber magnolia50.00 16.6733.3333.33
European alder50.00 50.00 0.00 0.00
Quaking aspen50.00 50.00 0.00 0.00
Weeping willow50.00 33.33 0.0016.67
Ohio buckeye58.33 29.17 0.0012.50
Empress tree58.82 41.18 0.00 0.00
Cornelian cherry59.26 3.7033.33 3.70
Crepe myrtle60.00 40.00 0.00 0.00
Eastern cottonwood60.00 30.00 0.0020.00
Black walnut60.61 39.39 3.03 0.00
Japanese tree lilac62.02 22.48 8.5310.85
Honeylocust62.15 25.50 6.2810.66
Japanese hornbeam64.52 25.81 3.23 9.68
Green ash65.45 26.88 1.04 8.83
Cockspur hawthorn66.67 33.33 0.0033.33
Crimson king maple66.67 33.33 0.0016.67
Oklahoma redbud66.67 33.33 0.00 0.00
Paperbark maple66.67 13.33 6.6720.00
Virginia pine66.67 33.33 0.00 0.00
Norway maple67.24 27.93 1.03 7.93
Callery pear67.60 20.87 7.02 8.17
Eastern redbud 92.004.0004.00
River birch 92.593.7003.70
Magnolia 93.105.1701.72
Bur oak 94.442.7802.78
American hornbeam 95.293.5301.18
Crab apple 96.342.7501.14
Eastern redcedar 97.620.0002.38
Hawthorn 97.720.9101.37
European hornbeam 98.200.0001.80
American larch100.000.0000.00
Arborvitae100.000.0000.00
Bigtooth aspen100.000.0000.00
Black pine100.000.0000.00
Blue spruce100.000.0000.00
Douglas-fir100.000.0000.00
Himalayan cedar100.000.0000.00
Kousa dogwood100.000.0000.00
Osage-orange100.000.0000.00
Persian ironwood100.000.0000.00
Pignut hickory100.000.0000.00
Pine100.000.0000.00
Pitch pine100.000.0000.00
Pond cypress100.000.0000.00
Red horse chestnut100.000.0000.00
Red pine100.000.0000.00
Scots pine100.000.0000.00
Smoketree100.000.0000.00
Southern red oak100.000.0000.00
Spruce100.000.0000.00
Two-winged silverbell100.000.0000.00

Species’ distribution of trunk problems

trees %>%
	select(spc_common, trunk_wire:trnk_other) %>%
	filter(spc_common != "null",
           if_all(-spc_common, ~ .x != "null")) %>%
	mutate(across(trunk_wire:trnk_other, ~ ifelse(.x == "Yes", 1, 0)),
           no_problem = ifelse(trunk_wire == 0 &
                               trnk_light == 0 &
                               trnk_other == 0, 1, 0)) %>%
	group_by(spc_common) %>%
	summarize(no_problem = 100*sum(no_problem)/n(),
              trunk_wire = 100*sum(trunk_wire)/n(),
              trnk_light = 100*sum(trnk_light)/n(),
              trnk_other = 100*sum(trnk_other)/n()) %>%
	arrange(no_problem) %>%
    mutate_if(is.numeric, ~(round(., digits = 2)))
A tibble: 128 × 5
spc_commonno_problemtrunk_wiretrnk_lighttrnk_other
<chr><dbl><dbl><dbl><dbl>
Tartar maple41.67 0.00 0.0058.33
Oklahoma redbud44.4411.11 0.0044.44
Horse chestnut63.6418.18 0.0018.18
Cockspur hawthorn66.6733.33 0.00 0.00
Crimson king maple66.67 0.00 0.0033.33
Paperbark maple66.67 0.00 0.0033.33
Hedge maple69.57 4.35 0.0026.09
Japanese snowbell73.33 0.00 0.0026.67
Pond cypress75.00 0.00 0.0025.00
Silver maple77.46 8.45 0.0014.08
Ohio buckeye79.17 0.00 0.0020.83
Eastern cottonwood80.00 0.00 0.0020.00
Pitch pine80.00 0.00 0.0020.00
Silver birch80.0010.0010.0010.00
Maple81.08 0.0010.81 8.11
Tulip-poplar82.35 0.00 0.0017.65
Paper birch82.98 2.13 0.0014.89
European beech83.33 0.00 0.0016.67
Mimosa83.3316.67 0.00 0.00
Green ash84.16 3.77 0.3912.21
Dawn redwood84.92 2.01 0.0013.57
Japanese hornbeam85.48 4.84 1.61 8.06
Eastern hemlock85.71 0.00 0.0014.29
Southern red oak85.71 0.00 0.0014.29
Sweetgum86.78 2.64 0.4410.13
Sophora87.22 1.46 0.4911.34
Chinese tree lilac87.50 0.00 0.0012.50
London planetree87.70 0.68 0.1511.69
Black walnut87.88 0.00 0.0012.12
Ginkgo87.92 1.69 0.5510.17
Blue spruce100000
Boxelder100000
Catalpa100000
Chinese fringetree100000
Crepe myrtle100000
Cucumber magnolia100000
Douglas-fir100000
Eastern redcedar100000
European alder100000
Himalayan cedar100000
Holly100000
Japanese maple100000
Kousa dogwood100000
Norway spruce100000
Osage-orange100000
Persian ironwood100000
Pignut hickory100000
Pine100000
Quaking aspen100000
Red horse chestnut100000
Red pine100000
Scots pine100000
Smoketree100000
Southern magnolia100000
Spruce100000
Sycamore maple100000
Turkish hazelnut100000
Two-winged silverbell100000
Virginia pine100000
White pine100000

Species’ distribution of branch problems

trees %>%
	select(spc_common, brch_light:brch_other) %>%
	filter(spc_common != "null",
           if_all(-spc_common, ~ .x != "null")) %>%
	mutate(across(brch_light:brch_other, ~ ifelse(.x == "Yes", 1, 0)),
           no_problem = ifelse(brch_light == 0 &
                               brch_shoe == 0 &
                               brch_other == 0, 1, 0)) %>%
	group_by(spc_common) %>%
	summarize(no_problem = 100*sum(no_problem)/n(),
              brch_light = 100*sum(brch_light)/n(),
              brch_shoe = 100*sum(brch_shoe)/n(),
              brch_other = 100*sum(brch_other)/n()) %>%
	arrange(no_problem) %>%
    mutate_if(is.numeric, ~(round(., digits = 2)))
A tibble: 128 × 5
spc_commonno_problembrch_lightbrch_shoebrch_other
<chr><dbl><dbl><dbl><dbl>
Boxelder50.00 0.000.0050.00
Crimson king maple50.00 0.000.0050.00
European alder50.00 0.000.0050.00
Tartar maple50.00 8.330.0050.00
Maple67.5710.810.0021.62
Southern magnolia68.42 0.000.0031.58
Sassafras70.59 5.880.0029.41
Turkish hazelnut70.59 0.000.0029.41
American beech72.73 4.550.0022.73
Paperbark maple73.33 0.000.0026.67
Silver maple74.65 0.000.0025.35
Ohio buckeye75.00 0.000.0025.00
Kentucky yellowwood77.78 0.000.0022.22
Oklahoma redbud77.78 0.000.0022.22
Pagoda dogwood77.78 0.000.0022.22
Arborvitae80.00 0.000.0020.00
Crepe myrtle80.00 0.000.0020.00
Eastern cottonwood80.00 0.000.0020.00
Silver birch80.0020.000.00 0.00
Sugar maple81.25 2.080.0016.67
Cornelian cherry81.48 3.700.0014.81
Horse chestnut81.82 0.000.0018.18
Amur maple83.33 0.000.0016.67
European beech83.33 0.000.0016.67
Callery pear83.92 2.320.1114.13
Paper birch85.11 2.130.0012.77
Honeylocust85.21 2.180.1412.83
Tulip-poplar85.29 0.000.0014.71
Japanese snowbell86.67 0.000.0013.33
Katsura tree86.84 0.000.0013.16
Bigtooth aspen100000
Black maple100000
Black pine100000
Blackgum100000
Blue spruce100000
Chinese tree lilac100000
Cockspur hawthorn100000
Douglas-fir100000
Eastern hemlock100000
Himalayan cedar100000
Kousa dogwood100000
Norway spruce100000
Osage-orange100000
Persian ironwood100000
Pignut hickory100000
Pine100000
Pitch pine100000
Pond cypress100000
Quaking aspen100000
Red horse chestnut100000
Red pine100000
River birch100000
Scots pine100000
Serviceberry100000
Smoketree100000
Southern red oak100000
Spruce100000
Two-winged silverbell100000
Virginia pine100000
White pine100000

Ranking of all 128 tree species

spc_first_ranking %>%
	select(-abd_rank)
A tibble: 128 × 7
spc_commonabundancehealth_indexmedian_tree_dbhhi_rankdbh_rankrank_sum
<chr><int><dbl><dbl><dbl><dbl><dbl>
Smoketree 11.000000011.0 6.5 8.0 7.25
Black maple 100.966666711.013.0 8.010.50
Amur cork tree 80.958333311.014.0 8.011.00
Siberian elm 1560.931623911.023.0 8.015.50
Pitch pine 51.0000000 8.0 6.526.516.50
Red horse chestnut 11.0000000 8.0 6.526.516.50
Willow oak 8890.936632910.021.013.017.00
Honeylocust131750.9387223 9.020.019.519.75
American elm 16980.918531612.036.0 4.020.00
Pin oak 45840.9282286 9.027.019.523.25
Tree of heaven 1040.913461511.039.0 8.023.50
White ash 500.9200000 9.533.015.024.00
Black locust 2590.917631910.037.013.025.00
Black walnut 330.9191919 9.034.019.526.75
Sophora 44530.9187813 9.035.019.527.25
Ohio buckeye 240.902777811.047.0 8.027.50
Japanese maple 110.9393939 6.019.040.029.50
Crepe myrtle 51.0000000 5.0 6.555.030.75
Red pine 11.0000000 5.0 6.555.030.75
Weeping willow 120.888888914.062.0 1.031.50
Golden raintree 3590.9554318 5.015.055.035.00
Schumard's oak 1370.9221411 6.031.040.035.50
Sawtooth oak 3530.9471199 5.017.055.036.00
Green ash 7700.8961039 9.053.019.536.25
European beech 61.0000000 4.5 6.567.036.75
Southern magnolia 190.9298246 5.024.055.039.50
Callery pear 72970.8923759 8.056.026.541.25
Crab apple 4370.9260107 5.028.055.041.50
London planetree 41220.845867713.081.0 2.541.75
Chinese elm 7850.9053079 6.044.040.042.00
Flowering dogwood 650.84102564.0 83.0 87.0 85.00
European alder 20.50000005.5127.5 45.0 86.25
Red maple3560.83895134.0 86.0 87.0 86.50
Chinese fringetree 90.88888893.0 62.0113.0 87.50
Mimosa 120.88888893.0 62.0113.0 87.50
Cockspur hawthorn 30.66666675.0120.5 55.0 87.75
Cucumber magnolia 120.77777784.5109.0 67.0 88.00
Amur maple 300.83333334.0 90.0 87.0 88.50
Bald cypress 890.82771544.0 94.0 87.0 90.50
Boxelder 20.50000005.0127.5 55.0 91.25
Dawn redwood1990.81574544.0 96.0 87.0 91.50
Empress tree 170.80392164.0 97.0 87.0 92.00
American beech 220.84848483.5 80.0105.0 92.50
Hardy rubber tree 660.86363643.0 74.0113.0 93.50
Japanese snowbell 150.80000004.0100.0 87.0 93.50
Turkish hazelnut 170.78431374.0103.5 87.0 95.25
Tulip-poplar 340.76470594.0112.0 87.0 99.50
Common hackberry1700.83529413.0 87.0113.0100.00
Maple 370.70270274.0117.0 87.0102.00
Himalayan cedar 60.83333332.0 90.0125.5107.75
Sassafras 170.78431373.0103.5113.0108.25
Kentucky yellowwood 180.77777783.0109.0113.0111.00
Norway spruce 30.77777783.0109.0113.0111.00
Horse chestnut 110.75757583.0114.0113.0113.50
Pagoda dogwood 180.74074073.0115.0113.0114.00
Paperbark maple 150.66666673.0120.5113.0116.75
Spruce 10.66666673.0120.5113.0116.75
Eastern hemlock 70.52380953.0126.0113.0119.50
Douglas-fir 20.66666672.0120.5125.5123.00
Pond cypress 120.55555562.5124.5122.0123.25

Ranking of all tree species with at least 29 abundances

spc_second_ranking %>%
	select(-abd_rank)
A tibble: 64 × 7
spc_commonabundancehealth_indexmedian_tree_dbhhi_rankdbh_rankrank_sum
<chr><int><dbl><dbl><dbl><dbl><dbl>
Siberian elm 1560.931623911.0 6 3.5 9.5
Willow oak 8890.936632910.0 5 6.011.0
Honeylocust131750.9387223 9.0 412.016.0
American elm 16980.918531612.017 2.019.0
Pin oak 45840.9282286 9.0 912.021.0
White ash 500.9200000 9.514 8.022.0
Tree of heaven 1040.913461511.019 3.522.5
Black locust 2590.917631910.018 6.024.0
Black walnut 330.9191919 9.01512.027.0
Sophora 44530.9187813 9.01612.028.0
Golden raintree 3590.9554318 5.0 130.031.0
Sawtooth oak 3530.9471199 5.0 230.032.0
Schumard's oak 1370.9221411 6.01222.534.5
Crab apple 4370.9260107 5.01030.040.0
Green ash 7700.8961039 9.03112.043.0
Chinese elm 7850.9053079 6.02422.546.5
Japanese zelkova 35960.9048016 6.02622.548.5
Kentucky coffeetree 3480.9415709 4.0 347.550.5
Callery pear 72970.8923759 8.03416.550.5
Ash 580.867816110.045 6.051.0
London planetree 41220.845867713.050 1.051.0
Mulberry 680.8774510 9.04112.053.0
Cherry 8690.9048715 5.02530.055.0
Hawthorn 2190.9284627 4.0 847.555.5
Ginkgo 58590.8882631 8.03916.555.5
American hophornbeam 840.8888889 7.53818.056.0
Magnolia 1160.9022989 5.02730.057.0
Shingle oak 2050.9252033 4.01147.558.5
Japanese hornbeam 620.8924731 5.03330.063.0
Silver linden 5410.8761553 6.04222.564.5
Amur maackia 590.909604542247.5 69.5
Bur oak 360.907407442347.5 70.5
Norway maple 2900.801149496012.0 72.0
American linden15830.842703765122.5 73.5
Swamp white oak 6810.920704831362.5 75.5
Black oak 1920.901041742847.5 75.5
Littleleaf linden33330.828182875719.0 76.0
Eastern redbud 500.900000042947.5 76.5
Scarlet oak 710.896713643047.5 77.5
Black cherry 320.895833343247.5 79.5
Purple-leaf plum 1100.890909143547.5 82.5
Sugar maple 480.840277855330.0 83.0
European hornbeam 1670.890219643647.5 83.5
Katsura tree 380.780701866222.5 84.5
Serviceberry 380.885964944047.5 87.5
Japanese tree lilac 1290.870801044347.5 90.5
Silver maple 710.784037656130.0 91.0
'Schubert' chokecherry 1630.869120744447.5 91.5
White oak 2410.858921244747.5 94.5
Paper birch 470.858156044847.5 95.5
Sweetgum 2270.850220344947.5 96.5
Flowering dogwood 650.841025645247.5 99.5
Red maple 3560.838951345447.5101.5
Amur maple 300.833333345647.5103.5
Bald cypress 890.827715445847.5105.5
Dawn redwood 1990.815745445947.5106.5
Hardy rubber tree 660.863636434662.5108.5
Tulip-poplar 340.764705946347.5110.5
Maple 370.702702746447.5111.5
Common hackberry 1700.835294135562.5117.5

Codes

# ---------- Packages & Datasets

# Load pre-installed, required packages
suppressPackageStartupMessages(library(tidyverse)) 
suppressPackageStartupMessages(library(dplyr)) 
suppressPackageStartupMessages(library(ggplot2))
suppressPackageStartupMessages(library(sf))
suppressPackageStartupMessages(library(geojsonsf))
suppressPackageStartupMessages(library(scales))

# Install & load the 'rwantshue' package for generating random color scheme
suppressWarnings(suppressMessages(install.packages("remotes")))
suppressWarnings(suppressMessages(remotes::install_github("hoesler/rwantshue", auth_token = "")))
suppressPackageStartupMessages(library(rwantshue))

# Install & load the 'ggfun' package for round rectangle borders and backgrounds in ggplots
suppressWarnings(suppressMessages(install.packages("ggfun", verbose=TRUE, quiet=TRUE)))
suppressPackageStartupMessages(library(ggfun))

# Install & load the 'ggchicklet' package for bar charts with rounded corners
suppressWarnings(suppressMessages(remotes::install_github("hrbrmstr/ggchicklet", auth_token = "")))
suppressPackageStartupMessages(library("ggchicklet"))

# Read the 'trees' data set from the CSV file
trees <- readr::read_csv('data/trees.csv', show_col_types = FALSE) %>%
	mutate(spc_common = str_to_sentence(spc_common))

# Read the 'neighborhoods' data set from the SHP file
neighborhoods <- st_read("data/nta.shp", quiet=TRUE) %>% 
	dplyr::select(boroname, ntacode, ntaname, geometry, shape_area)

# Create a merged data frame for the 'trees' and 'neighborhoods' data sets
merged_trees_and_neighborhoods <- trees %>%
	full_join(neighborhoods, by = c("nta"="ntacode", "nta_name"="ntaname"))


# ---------- Results & Discussion

# ----- Tree Population

# -- Spatial

# Top 10 NTAs in terms of land size 
top_nta_area <- neighborhoods %>%
	filter(boroname == "Manhattan", ntacode != "MN99") %>%
	arrange(desc(shape_area)) %>%
    slice(1:10)

# Tree count per neighborhood
nbh_tree_cnts <- merged_trees_and_neighborhoods %>%
	filter(boroname == "Manhattan", nta != "MN99") %>%
	group_by(nta, nta_name) %>%
	summarize(number_of_trees = n(), .groups = "keep") %>%
	arrange(desc(number_of_trees)) %>%
	ungroup() %>%
    mutate(proportion = round(number_of_trees/sum(number_of_trees), digits = 4))

# Species richness per neighborhood
nbh_rchns <- trees %>%
	filter(!(spc_common == "null")) %>%
	group_by(nta, nta_name) %>%
	summarize(richness = n_distinct(spc_common), .groups = "keep") %>%
	arrange(desc(richness)) %>%
	ungroup()

# Data for maps
nbhs_map <- nbh_tree_cnts %>%
	full_join(neighborhoods, c("nta" = "ntacode", "nta_name" = "ntaname")) %>% 
	full_join(nbh_rchns, c("nta", "nta_name")) %>%
	mutate(borough = substr(nta, 1, 2),
           nta_code_and_name = paste(nta, nta_name, sep=": "),
           nta_and_tree_cnt = ifelse(number_of_trees < 1000, 
           paste(nta,  " - ", "   ", prettyNum(number_of_trees,big.mark=","), " : ", nta_name, sep=""),
           paste(nta,  " - ", prettyNum(number_of_trees, big.mark=","), " : ", nta_name, sep="")
                                      ),
           nta_and_rchns = paste(nta,  " - ", prettyNum(richness, big.mark=","),
                                 " : ", nta_name, sep="")
          ) %>%
	st_as_sf %>%
	st_transform("+proj=longlat +ellps=intl +no_defs +type=crs") 

# Colorize the NTAs
color_scheme <- iwanthue(seed=1234, force_init=TRUE)
nta_colors <- color_scheme$hex(nrow(nbhs_map %>%  filter(borough == "MN")))

# Data of tree locations 
tree_locs <- trees %>%
	st_as_sf(coords = c("longitude", "latitude"), crs=4326) %>%
	st_transform("+proj=longlat +ellps=intl +no_defs +type=crs") 

# Map of tree locations by neighborhood
tree_locs_map_plot <- ggplot() + 
	geom_sf(data = nbhs_map,
            fill="#E8EAED", color="grey") +
    stat_sf_coordinates(data = tree_locs, 
                        aes(color = paste(nta, nta_name, sep=": ")),
                        size=0.001
                        ) +
    stat_sf_coordinates(data = nbhs_map %>% filter(borough=="MN", nta!="MN99"),
                        color="grey25", size=0.25) +
	geom_sf(data = nbhs_map %>% filter(borough=="MN", nta!="MN99"),
            color="grey25",
            alpha=0.1) + 
    theme(legend.position = c(0.024, 0.5),
          legend.justification=0.0,
          legend.key.width = unit(2.5, 'mm'),
	      legend.key.height = unit(1.8, 'mm'), 
          legend.direction="vertical",
          legend.background= element_roundrect(r = grid::unit(0.02, "snpc"),
                                               fill=alpha("#FFFFFF", 0.90)),
          legend.key = element_rect(fill=NA),
          legend.text = element_text(margin = margin(r=5, unit="pt"),
        	                         color="#65707C",
                                     family="sans serif"),
          legend.title = element_text(face="bold",
                                      color="#65707C",
                                      size=8.5,
                                      family="sans serif"),
		  axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color="#65707C",
                                   size=7,
                                   family="sans serif"),
          axis.text.x = element_text(angle=90,
                                     vjust=0.5,
                                     hjust=1),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          
          panel.border = element_rect(color="grey40",
                                      fill=NA),  
          panel.spacing = unit(2, "lines"),
          panel.background  = element_roundrect(r = grid::unit(0.001, "snpc"),
                                               fill=alpha("#9CC0F9", 1)),
          plot.title = element_text(color="#65707C",
                                    hjust=-4.5,
                                    vjust=10,
                                    size=14,
                                    family="sans serif")) +
		 labs(x="", y="", color="    Code: Name") +
		 ggtitle("Fig. 1: Map of the Tree Locations by Neighborhood in Manhattan") +
	scale_x_continuous(expand = c(0.01, 0),
                       limits = c(-74.25, -73.89), 
                       breaks = seq(-74.25, -73.89, by=0.02)) +
	scale_y_continuous(expand = c(0.01, 0),
                       limits = c(40.68, 40.88), 
                       breaks = seq(40.68, 40.88, by=0.02)) +
    guides(color = guide_legend(ncol=1,
                                override.aes = list(shape=15,
                                                    size=2.5
                                                    ))) +
	ggrepel::geom_label_repel(data = nbhs_map %>% filter(borough == "MN", nta != "MN99"),
                              aes(label = nta, geometry = geometry),
                              stat="sf_coordinates",
                              min.segment.length=0,
                              size=2,
                              label.size=NA,
                              alpha=0.6) +
	coord_sf(xlim = c(-74.25, -73.89), ylim = c(40.68, 40.88)) +
	scale_color_manual(values = nta_colors)

# Order legend items by number of trees
nbhs_map$nta_and_tree_cnt <- factor(
    nbhs_map$nta_and_tree_cnt,
       levels = nbhs_map$nta_and_tree_cnt,
       ordered=TRUE)

# Map of NTAs' tree counts
nbhs_tree_cnts_map_plot <- ggplot() + 
	geom_sf(data = nbhs_map %>% filter(borough != "MN" | nta == "MN99"),
            fill="#E8EAED", color="grey") +
	geom_sf(data = nbhs_map %>% filter(borough == "MN", nta != "MN99"),
            aes(fill = number_of_trees,
                color = nta_and_tree_cnt
           )) + 
    stat_sf_coordinates(data = nbhs_map %>% filter(nta %in% for_table_nbh_tree_cnts$nta),
                        color="grey25", size=0.5) +
    theme(legend.position = c(0.369, 0.5), 
          legend.justification=0.0,
          legend.key.width = unit(2.5, 'mm'),
	      legend.key.height = unit(1.8, 'mm'), 
          legend.direction="vertical",
          legend.background = element_roundrect(r = grid::unit(0.02, "snpc"),
                                               fill = alpha("#FFFFFF", 0.90)),
          legend.key = element_rect(fill=NA),
          legend.text = element_text(margin = margin(r=5, unit="pt"),
                                     size=7.9,
        	                         color="#65707C",
                                     family="sans serif"),
          legend.title = element_text(face="bold",
                                      color="#65707C",
                                      size=8.5,
                                      family="sans serif"),
          axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color="#65707C",
                                   size=7,
                                   family="sans serif"),
          axis.text.x = element_text(angle=90,
                                     vjust=0.5,
                                     hjust=1),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          
          panel.border = element_rect(color="grey40",
                                      fill=NA),  
          panel.spacing = unit(2, "lines"),
          panel.background  = element_roundrect(r = grid::unit(0.001, "snpc"),
                                               fill = alpha("#9CC0F9", 1)),
          plot.title = element_text(color="#65707C",
                                    hjust=4.2,
                                    vjust=10,
                                    size=14,
                                    family="sans serif")) +
		 labs(x="", y="", color="   Code - Number of trees : Name"
             ) +
		 ggtitle("Fig. 2: Map of the Number of Trees in Manhattan's Neighborhoods") +
	scale_x_continuous(expand = c(0.01, 0),
                       limits = c(-74.04, -73.64), 
                       breaks = seq(-74.04, -73.64, by=0.02)) +
	scale_y_continuous(expand = c(0.01, 0),
                       limits = c(40.68, 40.88), 
                       breaks = seq(40.68, 40.88, by=0.02)) +
	scale_color_manual(values = replicate(28, "grey25")) +
	scale_fill_gradient2(low = muted("499F78"),
                         high = muted("#216968")) +
	ggrepel::geom_label_repel(data = nbhs_map %>% filter(nta %in% for_table_nbh_tree_cnts$nta),
                              aes(label = nta, geometry = geometry),
                              stat="sf_coordinates",
                              min.segment.length=0,
                              label.size=NA,
                              alpha=0.5) +
	coord_sf(xlim = c(-74.04, -73.64), ylim = c(40.68, 40.88))

# Extract NTA fill colors
color_scheme_2 <- as.data.frame(ggplot_build(nbhs_tree_cnts_map_plot)$data[[2]])$fill

# Apply extracted fill colors to the legend
nbhs_tree_cnts_map_plot1 <- nbhs_tree_cnts_map_plot +
	guides(fill = "none",
           color = guide_legend(ncol=1,
                                override.aes = list(color = NA,
                                                    fill = color_scheme_2,
                                                    linewidth=0)))


# Tree count per curb location
number_of_trees_per_curb_loc <- merged_trees_and_neighborhoods %>%
	filter(str_detect(nta, "MN") & !(nta == "MN99")) %>%
	group_by(curb_loc) %>%
	summarize(number_of_trees = n()) %>%
	arrange(desc(number_of_trees)) %>%
    mutate(percentage = label_percent(accuracy=0.01)(number_of_trees/length(merged_trees_and_neighborhoods$tree_id)))

# OnCurb tree population
on_curb_stat <- number_of_trees_per_curb_loc %>%
    mutate(proportion = number_of_trees/sum(number_of_trees)) %>% 
	filter(proportion == max(abs(proportion)))

# Create a stacked bar plot for the curb location
curb_loc_stacked_bar_plot <- ggplot(number_of_trees_per_curb_loc) + 
	geom_chicklet(aes(x="", y = number_of_trees/sum(number_of_trees),
                      fill = curb_loc), 
                  radius = grid::unit(0.75, "mm"),
                  position="stack") +
	coord_flip() +
	theme(legend.position="right",
          legend.justification="top",
          legend.direction="vertical",
          legend.key.size = unit(0, 'pt'),
          legend.key = element_rect(fill=NA),
          legend.text = element_text(margin = margin(r = 4, unit = "pt"),
                                     color = "#65707C",
                                     family="sans serif"),
          legend.title = element_text(color = "#65707C",
                                      face="bold",
                                      size = 9,
                                      family="sans serif"),
		  axis.title.x = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
		  axis.title.y = element_blank(),
          axis.text = element_blank(),
          axis.line = element_blank(),
          axis.ticks = element_blank(),
          panel.grid.minor = element_blank(),
          panel.grid.major = element_blank(),
          panel.background = element_blank(),
          plot.subtitle = element_text(color="#65707C",
                                    hjust=0.25,
                                    size=10,
                                    family="sans serif"),
          plot.title = element_text(color="#65707C",
                                    hjust=-0.15,
                                    size=14,
                                    family="sans serif"),
		  plot.margin = unit(c(0,1,0,1), "cm")) +	
	scale_fill_manual(values = c("#875826",
                                 "#10401B")) + 
	ggtitle("\nFig. 3: Proportional Stacked Bar Graph of Tree Bed Location ",
            subtitle="  (in relation to the Curb)\n") +
	labs(y="\n%  \n(Number of trees)\n", fill="Location:  ") +
    guides(fill = guide_legend(nrow=2,
                               reverse=TRUE,
                               override.aes = list(shape = 15,
                                                   size = 4))) +
	scale_x_discrete(expand = c(0.01, 0)) +
	ggrepel::geom_text_repel(data = on_curb_stat,
                             aes(label = paste(label_percent(accuracy=0.01)(proportion),
                                       "\n (", prettyNum(number_of_trees,
                                                  big.mark=","),")",
                                       sep=""),
                                 x = "",
                                 y = 0.50 * proportion - 0.075),
                             size=5, color="white", hjust=1)


# Curb location per neighborhood
curb_loc_per_nbh <- merged_trees_and_neighborhoods %>% 
	filter(str_detect(nta, "MN") & !(nta == "MN99")) %>%
	group_by(nta, nta_name, curb_loc) %>%
	summarize(number_of_trees=n(), .groups="keep") %>%
	group_by(nta) %>%
	mutate(proportion = number_of_trees/sum(number_of_trees),
           percentage = label_percent(accuracy=0.01)(proportion)) %>%
	arrange(desc(proportion)) %>%
	ungroup()

# Higher between OnCurb and OffsetFromCurb per neighborhood
oncurb_vs_offset_per_nbh <- curb_loc_per_nbh %>% 
	group_by(nta) %>%
	filter(proportion == max(abs(proportion)))

# Order by NTA
curb_loc_per_nbh$nta_name <- factor(
    curb_loc_per_nbh$nta_name,
       levels = rev(unique(curb_loc_per_nbh$nta_name)),
       ordered=TRUE)

# Create a stacked bar plot for the curb location per neighborhood
curb_loc_per_nbh_stacked_bar_plot <- ggplot(curb_loc_per_nbh) + 
	geom_chicklet(aes(x = nta_name, y = proportion*100, fill = curb_loc), 
                  radius = grid::unit(0.75, "mm"), position="stack") +
	coord_flip() +
	theme(legend.position="right",
          legend.justification="top",
          legend.direction="vertical",
          legend.key.size = unit(0, "pt"),
          legend.key = element_rect(fill=NA),
          legend.text = element_text(margin = margin(r = 4, unit = "pt"),
                                     color="#65707C",
                                     family="sans serif"),
          legend.title = element_text(color="#65707C",
                                      face="bold",
                                      size=9,
                                      family="sans serif"),
		  axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text.x = element_text(color="#65707C",
                                   size=6,
                                   family="sans serif"),
          axis.text.y = element_text(color="#65707C",
                                   size=10,
                                   family="sans serif"),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.subtitle = element_text(color="#65707C",
                                    hjust=5.38,
                                    size=10,
                                    family="sans serif"),
          plot.title = element_text(color = "#65707C",
                                    hjust = 0.709,
                                    size= 12.2,
                                    family = "sans serif")) +
	scale_fill_manual(values = c("#875826",
                                 "#10401B")) +     
	ggtitle("\nFig. 4: Proportional Stacked Bar Graph of Each Neighborhood's Tree Bed Location",
            subtitle="               (in relation to the Curb)\n") +
	labs(x="\nNTA name \n", y="\nNTA code - % of on trees\n", fill="Location: ") +
    guides(fill = guide_legend(ncol=1,
                               reverse = TRUE,
                               override.aes = list(shape = 15,
                                                   size = 4))) +
	scale_y_continuous(expand = c(0.01, 0),
                       breaks = seq(0, 100, by=10)) +
	ggrepel::geom_text_repel(data = oncurb_vs_offset_per_nbh,
                             aes(label = paste(nta, " - ", 
                                               label_percent(accuracy=0.01)(proportion),
                                       sep=""),
                                 x = nta_name,
                                 y = ifelse(nta=="MN50", 100*proportion+22,
                                            100*proportion-22)),
                             size=2.2, color="white", hjust=1)


# -- Biological

# Size

# Summary statistics of the trunk diameter
tree_dbh_stats <- data.frame(N = length(trees$tree_dbh),
    						 mean = mean(trees$tree_dbh),
                             sd = sd(trees$tree_dbh),
                             min = min(trees$tree_dbh),
                             first_quartile = quantile(trees$tree_dbh, probs = 0.25),
                             median = median(trees$tree_dbh),
                             second_quartile = quantile(trees$tree_dbh, probs = 0.75),
                             max = max(trees$tree_dbh))
row.names(tree_dbh_stats) <- "tree_dbh" 

# Create a density curve of the trunk diameter
tree_dbh_dist_plot <- ggplot(trees, aes(x = tree_dbh)) + 
	geom_histogram(aes(y = after_stat(density)),
                   binwidth=1.1,
                   color=1,
                   fill="#5FBD5F") +
	geom_density(linewidth=0.85,
                 linetype=1,
                 colour = muted("5FBD5F"),
                 alpha=0.5) +

# Plot mean and median lines
	geom_vline(aes(xintercept = mean(tree_dbh)), col="red", size=0.6) +
	geom_vline(aes(xintercept = median(tree_dbh)), col="blue", size=0.6) +

	theme(axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color="#65707C",
                                   size=12,
                                   family="sans serif"),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.subtitle = element_text(color="#65707C",
                                    hjust=0.15,
                                    size=10,
                                    family="sans serif"),
          plot.title = element_text(color="#65707C",
                                    hjust=0.20,
                                    size=14,
                                    family="sans serif")) +
	ggtitle("\nFig. 5: Distribution of the Trunk Diameter") +
	labs(x="\nTrunk diameter in inches\n", y="\nDensity\n",
         subtitle="                (measured at 54 inches above the ground)\n") +
	scale_x_continuous(expand = c(0.01, 0), 
                       limits = c(0, 105),
                       breaks = seq(0, 105, by=10)) +
	scale_y_continuous(expand = c(0.01, 0),
                       limits = c(0, 0.12), 
                       breaks = seq(0, 0.12, by=0.02))


# Health-Related

# Status and health 
pop_status <- as.data.frame(table(trees$status)) %>%
	mutate(attribute = "status", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_health <- as.data.frame(table(trees$health)) %>%
	mutate(attribute = "health", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything()) %>%
	arrange(desc(proportion))

# Root problems
pop_root_stone <- as.data.frame(table(trees$root_stone)) %>%
	mutate(attribute = "root_stone", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_root_grate <- as.data.frame(table(trees$root_grate)) %>%
	mutate(attribute = "root_grate", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_root_other <- as.data.frame(table(trees$root_other)) %>%
	mutate(attribute = "root_other", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())

# Trunk problems
pop_trunk_wire <- as.data.frame(table(trees$trunk_wire)) %>%
	mutate(attribute = "trunk_wire", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_trnk_light <- as.data.frame(table(trees$trnk_light)) %>%
	mutate(attribute = "trnk_light", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_trnk_other <- as.data.frame(table(trees$trnk_other)) %>%
	mutate(attribute = "trnk_other", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())

# Branch problems
pop_brch_light <- as.data.frame(table(trees$brch_light)) %>%
	mutate(attribute = "brch_light", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_brch_shoe <- as.data.frame(table(trees$brch_shoe)) %>%
	mutate(attribute = "brch_shoe", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())
pop_brch_other <- as.data.frame(table(trees$brch_other)) %>%
	mutate(attribute = "brch_other", proportion = Freq/sum(Freq)) %>%
	rename(category = Var1, number_of_trees = Freq) %>%
	select(attribute, everything())

# Tree population's categorical health-related attributes
pop_attributes <- bind_rows(pop_status,
                            pop_health,
                            pop_root_stone,
                            pop_root_grate,
                            pop_root_other,
                            pop_trunk_wire,
                            pop_trnk_light,
                            pop_trnk_other,
                            pop_brch_light,
                            pop_brch_shoe,
                            pop_brch_other) %>%
                  mutate(percentage = label_percent(accuracy = 0.01)(proportion))  		

# Highest category per attribute
pop_attributes_highest_per_category <- pop_attributes %>%
	group_by(attribute) %>%
	filter(proportion == max(abs(proportion)))

# Order by attributes 
pop_attributes$attribute <- factor(
    pop_attributes$attribute,
       levels = rev(unique(pop_attributes$attribute)),
       ordered=TRUE)

# Order by categories 
pop_attributes$category <- factor(
    pop_attributes$category,
       levels = c("Dead", "Alive", "Fair", "Poor", "Good", "Yes", "No"),
       ordered=TRUE)

# Create a stacked bar plot of the tree population's categorical, health-related attributes
pop_attributes_stacked_bar_plot <- ggplot(pop_attributes) + 
	geom_chicklet(aes(x = attribute, y = proportion*100, fill = category), 
                  radius = grid::unit(0.75, "mm"), position="stack") +
	coord_flip() +
	theme(legend.position = "right",
          legend.justification="top",
          legend.direction="vertical",
          legend.key.size = unit(0, "pt"),
          legend.key = element_rect(fill = NA),
          legend.text = element_text(margin = margin(r = 4, unit = "pt"),
                                     color = "#65707C",
                                     family="sans serif"),
          legend.title = element_text(color = "#65707C",
                                      face = "bold",
                                      size = 9,
                                      family="sans serif"),
		  axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color="#65707C",
                                   size=12,
                                   family="sans serif"),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.title = element_text(color = "#65707C",
                                    hjust = 0.715,
                                    size= 13.75,
                                    family = "sans serif")) +
	scale_x_discrete(labels=c("Other problems (branch)",
                              "Shoes (branch)",
                              "Lights or wires (branch) ",
                              "Other problems (trunk)",
                              "Lighting installed (trunk)",
                              "Wires or rope (trunk)",
                              "Other problems (root)",
                              "Metal grates (root)",
                              "Paving stones (root)",
                              "Health",
                              "Status"))+
	scale_fill_manual(values = c("grey40",
                                 "#10401B",
                                 "#89E7B3",
								 "#40C17E",
                                 "#1F9153",
                                 "#9F2305",
                                 "#4E7A61"),
                     labels = c("Dead", "Alive", "Poor",  "Fair", "Good", "Yes", "No")) +
	ggtitle("\nFig. 6: Proportional Stacked Bar Graph of the Tree Population's Attributes\n") +
	labs(x="\nAttribute \n", y="\n%  \n(Number of trees) \n", fill="Category: ") +
    guides(fill = guide_legend(ncol=1,
                               override.aes = list(shape = 15,
                                                   size = 4))) +
	scale_y_continuous(expand = c(0.01, 0),
                       breaks = seq(0, 100, by=10)) +
	ggrepel::geom_text_repel(data = pop_attributes_highest_per_category,
                             aes(label = paste(percentage,
                                       "\n (", prettyNum(number_of_trees,
                                                  big.mark=","),")",
                                       sep=""),
                                 x = attribute,
                                 y = 100*proportion-20),
                             size=3, color="white", hjust=1)


# ----- Tree Species

# -- Biodiversity

# Richness

# Top 10 NTAs with the highest species richness
top_ten_nbh_rchns <- nbh_rchns %>%
	slice(1:10)

# Order by richness
nbhs_map$nta_and_rchns <- factor(
    nbhs_map$nta_and_rchns,
       levels = (nbhs_map %>% arrange(desc(richness)))$nta_and_rchns,
       ordered = TRUE)

# Map of NTAs' richness
nbh_rchns_map_plot <- ggplot() + 
	geom_sf(data = nbhs_map %>% filter(borough != "MN" | nta == "MN99"),
            fill="#E8EAED", color="grey") +
	geom_sf(data = nbhs_map %>% filter(borough == "MN", nta != "MN99"),
            aes(fill = richness,
                color = nta_and_rchns)) + 
    stat_sf_coordinates(data = nbhs_map %>% filter(borough == "MN", nta != "MN99") %>%
            	        	inner_join(nbh_rchns, by = c("nta", "nta_name")) %>%
                        	filter(nta %in% top_ten_nbh_rchns$nta),
                        color="grey25", size = 0.5) +
    theme(legend.position = c(0.3518, 0.5), 
          legend.justification=0.0,
          legend.key.width = unit(2.5, 'mm'),
	      legend.key.height = unit(1.8, 'mm'), 
          legend.direction="vertical",
          legend.background = element_roundrect(r = grid::unit(0.02, "snpc"),
                                               fill = alpha("#FFFFFF", 0.90)),
          legend.key = element_rect(fill=NA),
          legend.text = element_text(margin = margin(r=5, unit="pt"),
        	                         color="#65707C",
                                     family="sans serif"),
          legend.title = element_text(face="bold",
                                      color="#65707C",
                                      size=8.5,
                                      family="sans serif"),
          axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color="#65707C",
                                   size=7,
                                   family="sans serif"),
          axis.text.x = element_text(angle=90,
                                     vjust=0.5,
                                     hjust=1),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          
          panel.border = element_rect(color="grey40",
                                      fill=NA),  
          panel.spacing = unit(2, "lines"),
          panel.background  = element_roundrect(r = grid::unit(0.001, "snpc"),
                                               fill = alpha("#9CC0F9", 1)),
          plot.title = element_text(color="#65707C",
                                    hjust=1.8,
                                    vjust=10,
                                    size=14,
                                    family="sans serif")) +
		 labs(x="", y="", color="    Code - Richnesss : Name") +
		 ggtitle("Fig. 7: Map of Tree Species Richness of Manhattan's Neighborhoods") +
	scale_x_continuous(expand = c(0.01, 0),
                       limits = c(-74.04, -73.64), 
                       breaks = seq(-74.04, -73.64, by=0.02)) +
	scale_y_continuous(expand = c(0.01, 0),
                       limits = c(40.68, 40.88), 
                       breaks = seq(40.68, 40.88, by=0.02)) +
	scale_color_manual(values = replicate(28, "grey25")) +
	scale_fill_gradient2(low = "#E3EDE5",
                         high = "#068409") +
	ggrepel::geom_label_repel(data = nbhs_map %>% filter(nta %in% top_ten_nbh_rchns$nta),
                              aes(label = nta, geometry = geometry),
                              stat="sf_coordinates",
                              min.segment.length=0,
                              label.size=NA,
                              alpha=0.5) +
	coord_sf(xlim = c(-74.04, -73.64), ylim = c(40.68, 40.88))     

# Extract NTA fill colors
color_scheme_3 <- as.data.frame(ggplot_build(nbh_rchns_map_plot)$data[[2]])$fill

# Apply extracted fill colors to the legend
nbh_rchns_map_plot2 <- nbh_rchns_map_plot +
	guides(fill = "none",
           color = guide_legend(ncol=1,
                                override.aes = list(color = NA,
                                                    fill = color_scheme_3,
                                                    linewidth=0)))

# Abundance

# Species abundance and relative abundance
spc_abd <- trees %>% 
	group_by(spc_common) %>%
	summarize(abundance = n()) %>%  
	ungroup() %>%
	mutate(relative_abundance = abundance/sum(abundance)) %>%
	arrange(desc(abundance)) %>%
	arrange(spc_common == "null")

# Top 10 most abundant species
for_table_spc_abd <- spc_abd %>%
	slice(1:10) %>%
	mutate(abundance = prettyNum(abundance,big.mark=","),
           perc_relative_abundance = label_percent(accuracy=0.01)(relative_abundance))

# Bar graph for Top 25 tree species
top_species_bar_plot <- ggplot(spc_abd %>% slice(1:25)) + 
	geom_chicklet(aes(x = fct_reorder(spc_common,
                                    abundance),
                      y = abundance), 
                  fill="#10401B",
                  radius = grid::unit(1, "mm"), position="stack") +
	coord_flip() +
	theme(legend.position="none",
          axis.title = element_text(color = "#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color = "#65707C",
                                   size=12,
                                   family="sans serif"),
          axis.title.x = element_text(margin=margin(20,0,10,0)),
          axis.title.y = element_text(margin=margin(0,20,0,10)),
          axis.line = element_line(colour = "grey",
                                   linewidth = 0.5),
          panel.grid.major = element_line(color = "grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.title = element_text(color = "#65707C",
                                    hjust = 1.03,
                                    vjust = 4,
                                    size= 14,
                                    family = "sans serif",
                                    margin=margin(0,0,20,0))) +
	ggtitle("
\nFig. 8: Bar Graph of the 25 Most Abundant Tree Species in Manhattan ") +
	labs(x="Common name of the species", y="Abundance (% relative abundance)") +
	scale_y_continuous(expand = c(0.01, 0), limits = c(0,13500),
                      breaks = seq(0, 13500, by=2000)) +
	geom_text(aes(label = paste(prettyNum(abundance, big.mark=","),
                                " (", label_percent(accuracy=0.01)(relative_abundance),")",
                                sep=""),
                                 x = spc_common,
                                 y = ifelse(between(rank(desc(abundance)),3,10), abundance-807.5,
                                           ifelse(between(rank(desc(abundance)),2,2), abundance-880,
                                           ifelse(between(rank(desc(abundance)),1,1), abundance-980,
                                           ifelse(between(rank(desc(abundance)),11,11), abundance+770,
                                           abundance+670)))),
                  color = ifelse(between(rank(desc(abundance)),1,10), "white",
                                           "#65707C")),
              size = 2) +
	scale_color_manual(values=c("#65707C","white"))

# Identified species abundances
identified_spc_abd <- trees %>%
	filter(!is.na(spc_common)) %>%
	group_by(spc_common) %>%
	summarize(abundance = n())

# Summary statistics of species abundances
spc_abd_stats <- data.frame(number_of_identified_spc = length(identified_spc_abd$abundance),
    						mean = mean(identified_spc_abd$abundance),
                            sd = sd(identified_spc_abd$abundance),
                            min = min(identified_spc_abd$abundance),
                            first_quartile = quantile(identified_spc_abd$abundance, probs = 0.25),
                            median = median(identified_spc_abd$abundance),
                            third_quartile = quantile(identified_spc_abd$abundance, probs = 0.75),
                            max = max(identified_spc_abd$abundance))
row.names(spc_abd_stats) <- "spc_abundance" 

# Histogram with density curve of the species abundances
tree_count_per_species_dist_plot <- ggplot(identified_spc_abd,
                                           aes(x = abundance)) + 
	geom_histogram(aes(y = after_stat(density)),
                   binwidth=25,
                   color=1,
                   fill="#5FBD5F") + geom_density(linewidth=0.85,
                                                  linetype=1,
                                                  colour = muted("5FBD5F"),
                                                  alpha=0.5) +

# Plot mean and median
	geom_vline(aes(xintercept = mean(abundance)), col="red", size=0.6) +
	geom_vline(aes(xintercept = median(abundance)), col="blue", size=0.6) +

	theme(axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color="#65707C",
                                   size=12,
                                   family="sans serif"),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.subtitle = element_text(color="#65707C",
                                    hjust=-0.33,
                                    size=10,
                                    family="sans serif"),
          plot.title = element_text(color="#65707C",
                                    hjust=0.5,
                                    size=14,
                                    family="sans serif")) +
	ggtitle("\nFig. 16: Distribution of the Species Abundance                \n") +
	labs(x="\nSpecies abundance\n", y="\nDensity\n") +
	scale_x_continuous(expand = c(0.01, 0), 
                       limits = c(0, 2550),
                       breaks = seq(0, 2550, by=250)) +
	scale_y_continuous(expand = c(0.01, 0),
                       limits = c(0, 0.0081), 
                       breaks = seq(0, 0.0081, by=0.001))

# Species abundances per neighborhood
spc_abd_nbh <- nbh_spc_long %>%
	group_by(nta, nta_name) %>%
	filter(!(number_of_trees == 0)) %>%
	rename(abundance_wrt_nta = number_of_trees) %>%
	select(starts_with("nta"), spc_common, everything()) %>%
	mutate(relative_abundance_wrt_nta = label_percent(accuracy=0.01)(abundance_wrt_nta/sum(abundance_wrt_nta))) %>% 
	arrange(nta, desc(abundance_wrt_nta)) %>%
	ungroup()


# Diversity

# Simpson's Diversity Index (SDI)
mnh_sdi <- spc_abd %>%
	filter(!is.na(spc_common)) %>%
	select(-relative_abundance) %>%
	mutate(numerator = abundance*(abundance-1)) %>%
	summarize(SDI = 1-(sum(numerator)/(sum(abundance)*(sum(abundance)-1))),
              number_of_trees = sum(abundance),
              richness = n())


# -- Biology

# Size

# Summary statistics of species' tree DBHs
spc_tree_dbh_stats <- trees %>% 
	group_by(spc_common) %>%
	filter(!is.na(spc_common), !is.na(tree_dbh)) %>%
	summarize(abundance = n(),
              mean_tree_dbh = mean(tree_dbh),
              sd_tree_dbh = sd(tree_dbh),
              min_tree_dbh = min(tree_dbh),
              first_quartile_tree_dbh = quantile(tree_dbh, probs=0.25),
              median_tree_dbh = median(tree_dbh),
              third_quartile_tree_dbh = quantile(tree_dbh, probs=0.75),
              max_tree_dbh = max(tree_dbh))  %>%
	arrange(desc(median_tree_dbh))

# Create a bar plot for Top 25 tree species in terms of median dbh
top_spc_dbh_plot <- ggplot(top_spc_tree_dbh_stats %>% slice(1:25)) + 
	geom_chicklet(aes(x = fct_reorder(spc_common,
                                    median_tree_dbh),
                      y = median_tree_dbh), 
                  fill="#10401B",
                  radius = grid::unit(1, "mm"), position="stack") +
	coord_flip() +
	theme(axis.title = element_text(color = "#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text = element_text(color = "#65707C",
                                   size=12,
                                   family="sans serif"),
          axis.title.x = element_text(margin=margin(20,0,10,0)),
          axis.title.y = element_text(margin=margin(0,20,0,10)),
          axis.line = element_line(colour = "grey",
                                   linewidth = 0.5),
          panel.grid.major = element_line(color = "grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.title = element_text(color="#65707C",
                                    hjust=1.13,
                                    size=14,
                                    family="sans serif"),
          plot.subtitle = element_text(color="#65707C",
                                    hjust=2.95,
                                    size=10,
                                    family="sans serif")) +   
	ggtitle("\nFig. 9: Bar Graph of the Top 25 Largest Tree Species in Manhattan",
            subtitle="(in terms of median diameter at breast height (DBH) of 54 inches)    \n") +
	labs(x="\nCommon name of the species\n", y="Trunk diameter in inches\n") +
	scale_y_continuous(expand = c(0.01, 0),
                       limits = c(0, 15.5),
                       breaks = seq(0, 15.5, by=3)) +
	geom_text(aes(label = median_tree_dbh,
                                 x = spc_common,
                                 y = median_tree_dbh-0.4),
              size = 3, color = "white")

# Health-related

# Status per species
spc_status <- trees %>% 
	filter(!(is.na(spc_common) | is.na(spc_common))) %>%
	group_by(spc_common, status) %>%
	summarize(number_of_trees = n(), .groups="keep") %>%
	group_by(spc_common) %>%
	mutate(proportion_wrt_spc = number_of_trees/sum(number_of_trees),
           percentage_wrt_spc = label_percent(accuracy=0.01)(proportion_wrt_spc)) %>%
	arrange(proportion_wrt_spc) %>%
	select(-proportion_wrt_spc) %>%
	ungroup()

# Health per species
spc_health <- trees %>% 
	filter(!is.na(spc_common), !is.na(health)) %>%
	group_by(spc_common, health) %>%
	summarize(number_of_trees = n(), .groups="keep") %>%
	group_by(spc_common) %>%
	mutate(proportion = number_of_trees/sum(number_of_trees),
           percentage = label_percent(accuracy=0.01)(proportion),
           health = as.factor(health)) %>%
	arrange(spc_common, desc(proportion)) %>%
	ungroup()

# Health index per species
spc_health_index <- spc_health %>%
	group_by(spc_common) %>%
	mutate(health_score = ifelse(health=="Good", 3*number_of_trees,
                                 ifelse(health=="Fair", 2*number_of_trees,
                                        1*number_of_trees)),
          health_index = sum(health_score)/(3*sum(number_of_trees))) %>%
	ungroup() %>%
	select(spc_common, number_of_trees, health_index) %>%
	group_by(spc_common) %>%
	mutate(number_of_trees = sum(number_of_trees)) %>%
	distinct(spc_common, number_of_trees, health_index) %>%
	arrange(desc(health_index)) %>%
	rename(abundance = number_of_trees) %>%
	ungroup()

# Top 25 species in terms of health index
for_graph_top_spc_health <- spc_health %>%
	filter(spc_common %in% (
        spc_health_index %>%
        top_n(25, health_index))$spc_common) %>%
	arrange(desc(proportion))

# Order health per species
for_graph_top_spc_health$health <- factor(
    for_graph_top_spc_health$health,
    levels = c("Poor", "Fair", "Good"),
    ordered = TRUE)

# Order species by proportion of 'Good' health
for_graph_top_spc_health$spc_common <- factor(
    for_graph_top_spc_health$spc_common,
    levels = rev((for_graph_top_spc_health %>% filter(health == "Good"))$spc_common),
    ordered = TRUE)

# Highest percentage among species' health
top_spc_health_highest <- for_graph_top_spc_health %>% 
	group_by(spc_common) %>%
	filter(proportion == max(abs(proportion))) %>%
	ungroup()

# Create a stacked bar plot of the tree species' categorical, health-related attributes
top_spc_health_stacked_bar_plot <- ggplot(for_graph_top_spc_health) + 
	geom_chicklet(aes(x = spc_common, y = proportion*100, fill = health), 
                  radius = grid::unit(0.75, "mm"), position="stack") +
	coord_flip() +
	theme(legend.position = "right",
          legend.justification="top",
          legend.direction="vertical",
          legend.key.size = unit(0, 'pt'),
          legend.key = element_rect(fill = NA),
          legend.text = element_text(margin = margin(r = 4, unit = "pt"),
                                     color = "#65707C",
                                     family="sans serif"),
          legend.title = element_text(color = "#65707C",
                                      face="bold",
                                      size = 9,
                                      family="sans serif"),
		  axis.title = element_text(color="#65707C",
                                    face="bold",
                                    family="sans serif"),
          axis.text.x = element_text(color="#65707C",
                                   size=6,
                                   family="sans serif"),
          axis.text.y = element_text(color="#65707C",
                                   size=10,
                                   family="sans serif"),
          axis.line = element_line(colour="grey",
                                   linewidth=0.5),
          panel.grid.major = element_line(color="grey",
                                          linetype="dashed",
                                          linewidth=0.25),
          panel.background = element_blank(),
          plot.subtitle = element_text(color="#65707C",
                                    hjust=-2.15,
                                    size=10,
                                    family="sans serif"),
          plot.title = element_text(color = "#65707C",
                                    hjust = 0.74,
                                    size= 12,
                                    family = "sans serif")) +
	scale_fill_manual(values = c("#89E7B3",
								 "#40C17E",
                                 "#1F9153")) +     
	ggtitle("\nFig. 10: Proportional Stacked Bar Graph of the Top 25 Healthiest Tree Species",
            subtitle="               (in terms of Health Index (HI) value)\n") +
	labs(x="\nCommon name of the species\n", y="\n% relative abundance\n", fill="Health: ") +
    guides(fill = guide_legend(ncol=1,
                               override.aes = list(shape = 15,
                                                   size = 4))) +
	scale_y_continuous(expand = c(0.01, 0),
                       breaks = seq(0, 100, by=10)) +
	ggrepel::geom_text_repel(data = top_spc_health_highest %>% 
                             	inner_join(spc_health_index, by="spc_common"),
                             aes(label = paste("HI: ", round(health_index, digits=2),
                                               ", Good: ", label_percent(
                                                   accuracy=0.01)(proportion), sep=""),
                                 x = spc_common,
                                 y = ifelse(proportion==1, 100*proportion-21.5,
                                            100*proportion-22)),
                             size=2.2, color="white", hjust=1)

# Create a data for the graph of top 25 species in terms of root problems
spc_root_problems <- trees %>%
	select(spc_common, root_stone:root_other) %>%
	filter(spc_common != "null",
           if_all(-spc_common, ~ .x != "null")) %>%
	mutate(across(root_stone:root_other, ~ ifelse(.x == "Yes", 1, 0)),
           None = ifelse(root_stone == 0 &
                         root_grate == 0 &
                         root_other == 0, 1, 0)) %>%
	group_by(spc_common) %>%
	summarize(none = 100*sum(None)/n(),
              root_stone = 100*sum(root_stone)/n(),
              root_grate = 100*sum(root_grate)/n(),
              root_other = 100*sum(root_other)/n()) %>%
	rename(`Common name of the species` = spc_common,
           `''Paving stones` = root_stone,
           `'Metal grates` = root_grate,
           `Others` = root_other) %>% 
	ungroup() %>%
	filter(rank((none)) <= 25) %>%
	arrange((none)) %>%
    mutate_if(is.numeric, ~(round(., digits = 2))) %>%
	pivot_longer(cols = c(3:5), 
                 names_to = "Root problem",
                 values_to = "% of trees")

# Create a data for the graph of top 25 species in terms of trunk problems
spc_trunk_problems <- trees %>%
	select(spc_common, trunk_wire:trnk_other) %>%
	filter(spc_common != "null",
           if_all(-spc_common, ~ .x != "null")) %>%
	mutate(across(trunk_wire:trnk_other, ~ ifelse(.x == "Yes", 1, 0)),
           None = ifelse(trunk_wire == 0 &
                         trnk_light == 0 &
                         trnk_other == 0, 1, 0)) %>%
	group_by(spc_common) %>%
	summarize(none = 100*sum(None)/n(),
              trunk_wire = 100*sum(trunk_wire)/n(),
              trnk_light = 100*sum(trnk_light)/n(),
              trnk_other = 100*sum(trnk_other)/n()) %>%
	rename(`Common name of the species` = spc_common,
           `''Wires or rope` = trunk_wire,
           `'Lighting installed` = trnk_light,
           `Others` = trnk_other) %>% 
	ungroup() %>%
	filter(rank((none)) <= 25) %>%
	arrange((none)) %>%
    mutate_if(is.numeric, ~(round(., digits = 2))) %>%
	pivot_longer(cols = c(3:5), 
                 names_to = "Trunk problem",
                 values_to = "% of trees")

# Create a data for the graph of top 25 species in terms of branch problems
brch_trunk_problems <- trees %>%
	select(spc_common, brch_light:brch_other) %>%
	filter(spc_common != "null",
           if_all(-spc_common, ~ .x != "null")) %>%
	mutate(across(brch_light:brch_other, ~ ifelse(.x == "Yes", 1, 0)),
           None = ifelse(brch_light == 0 &
                         brch_shoe == 0 &
                         brch_other == 0, 1, 0)) %>%
	group_by(spc_common) %>%
	summarize(none = 100*sum(None)/n(),
              brch_light = 100*sum(brch_light)/n(),
              brch_shoe = 100*sum(brch_shoe)/n(),
              brch_other = 100*sum(brch_other)/n()) %>%
	rename(`Common name of the species` = spc_common,
           `''Lights or wires ` = brch_light,
           `'Shoes` = brch_shoe,
           `Others` = brch_other) %>% 
	ungroup() %>%
	filter(rank((none)) <= 25) %>%
	arrange((none)) %>%
    mutate_if(is.numeric, ~(round(., digits = 2))) %>%
	pivot_longer(cols = c(3:5), 
                 names_to = "Branch problem",
                 values_to = "% of trees")

# Ranking

# Correlation coefficient of health vs. size

# Spearman
spearman_corr <- data.frame(
    test_stat=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh,
         method = "spearman", exact = FALSE)$statistic,
    corr_coeff=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh,
         method = "spearman", exact = FALSE)$estimate,
    p_value=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh,
         method = "spearman", exact = FALSE)$p.value)

# Kendall
kendall_corr <- data.frame(
    test_stat=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh,
         method = "kendall", exact = FALSE)$statistic,
    corr_coeff=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh,
         method = "kendall", exact = FALSE)$estimate,
    p_value=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh,
         method = "kendall", exact = FALSE)$p.value)

# Pearson
pearson_corr <- data.frame(
    test_stat=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh)$statistic,
    corr_coeff=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh)$estimate,
    p_value=cor.test(spc_health_index$health_index, spc_tree_dbh_stats$median_tree_dbh)$p.value)

# Merge results
corr_coeffs <- spearman_corr %>%
    mutate(method = "Spearman") %>%
	bind_rows(kendall_corr %>%
              	mutate(method = "Kendall"), 
              pearson_corr %>%
                mutate(method = "Pearson")) %>%
	select(method, everything()) %>%
	mutate(p_value = formatC(p_value, format = "e", digits = 4))
rownames(corr_coeffs) <- 1:nrow(corr_coeffs)

# Rank all 128 species in terms of size & health 
spc_first_ranking <- spc_health_index %>%
	select(spc_common, abundance, health_index) %>%
	inner_join(trees %>% 
               group_by(spc_common) %>%
               filter(spc_common != "null", health != "null") %>%
               summarize(abundance = n(),
                         median_tree_dbh = median(tree_dbh)),
    	by = c("spc_common", "abundance")) %>%
	mutate(abd_rank = rank(desc(abundance)),
           hi_rank = rank(desc(health_index)),
           dbh_rank = rank(desc(median_tree_dbh)),
           rank_sum = (hi_rank + dbh_rank)) %>%
	arrange(rank_sum)

# Rank all species with abundances of 29 in terms of size & health 
spc_second_ranking <- spc_health_index %>%
	select(spc_common, abundance, health_index) %>%
	inner_join(trees %>% 
               group_by(spc_common) %>%
               filter(spc_common != "null", health != "null") %>%
               summarize(abundance = n(),
                         median_tree_dbh = median(tree_dbh)),
    	by = c("spc_common", "abundance")) %>%

# Filter out species with abundances less than the median abundances
	filter(abundance >= median(spc_tree_dbh_stats$abundance)) %>% 

	mutate(abd_rank = rank(desc(abundance)),
           hi_rank = rank(desc(health_index)),
           dbh_rank = rank(desc(median_tree_dbh)),
           rank_sum = (hi_rank + dbh_rank)) %>%
	arrange(rank_sum)

# Pivot 'spc_first_ranking' to a long format
spc_first_ranking_long <- spc_first_ranking %>%
	rename(`Common name of the species` = spc_common,
           `Health index` = health_index,
           `Median trunk dbh` = median_tree_dbh) %>%
	pivot_longer(cols = c(3:4), 
                 names_to = "Measurement",
                 values_to = "Value")

# Pivot 'spc_second_ranking' to a long format
spc_second_ranking_long <- spc_second_ranking %>%
	rename(`Common name of the species` = spc_common,
           `Health index` = health_index,
           `Median trunk dbh` = median_tree_dbh) %>%
	pivot_longer(cols = c(3:4), 
                 names_to = "Measurement",
                 values_to = "Value")

# Top 10 species in the first ranking 
top_spc_first_ranking <- spc_first_ranking_long %>%
	arrange(rank_sum) %>%
	filter(`Common name of the species` %in% (spc_first_ranking %>% slice(1:10))$spc_common)

# Top 10 species in the second ranking 
top_spc_second_ranking <- spc_second_ranking_long %>%
	arrange(rank_sum) %>%
	filter(`Common name of the species` %in% (spc_second_ranking %>% slice(1:10))$spc_common)
The following package(s) will be installed:
- remotes [2.5.0]
These packages will be installed into "~/renv/library/linux-ubuntu-jammy/R-4.4/x86_64-pc-linux-gnu".

# Installing packages --------------------------------------------------------
- Installing remotes ...                        OK [linked from cache]
Successfully installed 1 package in 9.3 milliseconds.



Error: Failed to install 'rwantshue' from GitHub:
  HTTP error 401.
  Bad credentials

  Rate limit remaining: 59/60
  Rate limit reset at: 2025-08-19 03:06:24 UTC

  
Traceback:


1. withCallingHandlers(expr, warning = function(w) if (inherits(w, 
 .     classes)) tryInvokeRestart("muffleWarning"))

2. suppressMessages(remotes::install_github("hoesler/rwantshue", 
 .     auth_token = ""))

3. withCallingHandlers(expr, message = function(c) if (inherits(c, 
 .     classes)) tryInvokeRestart("muffleMessage"))

4. remotes::install_github("hoesler/rwantshue", auth_token = "")

5. install_remotes(remotes, auth_token = auth_token, host = host, 
 .     dependencies = dependencies, upgrade = upgrade, force = force, 
 .     quiet = quiet, build = build, build_opts = build_opts, build_manual = build_manual, 
 .     build_vignettes = build_vignettes, repos = repos, type = type, 
 .     ...)

6. tryCatch(res[[i]] <- install_remote(remotes[[i]], ...), error = function(e) {
 .     stop(remote_install_error(remotes[[i]], e))
 . })

7. tryCatchList(expr, classes, parentenv, handlers)

8. tryCatchOne(expr, names, parentenv, handlers[[1L]])

9. value[[3L]](cond)

10. stop(remote_install_error(remotes[[i]], e))