Profiling Manhattan's Tree Population and Species
Photo by Roberto Lee Cortes
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!
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
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 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.
Results & Discussion
Tree Population
Using descriptive and spatial analyses, the following information outlines the location and physical attributes of all Manhattan trees in
Spatial
Tree Locations by Neighborhood:
While trees seem to cover much each of Manhattan's
- *Hudson Yards-Chelsea-Flatiron-Union Square (MN13)
- Upper West Side (MN12)
- *Midtown-Midtown South (MN17)
- Central Harlem North-Polo Grounds (MN03)
- West Village (MN23)
- *SoHo-TriBeCa-Civic Center-Little Italy (MN24)
- East Harlem North (MN34)
- *Lower East Side (MN28)
- Washington Heights South (MN36)
- Washington Heights North (MN35)
# ---------- 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 and load the 'rwantshue' package
# For generating random color scheme
devtools::install_github("hoesler/rwantshue")
suppressPackageStartupMessages(library(rwantshue))
# Install and load the 'ggfun' package
# For round rectangle borders and backgrounds in ggplots
install.packages("ggfun")
suppressPackageStartupMessages(library(ggfun))
# Install and load the 'ggchicklet' package
# For bar charts with rounded corners
install.packages("ggchicklet", repos = "https://cinc.rud.is")
suppressPackageStartupMessages(library("ggchicklet"))
# Install and load the 'patchwork' package
suppressWarnings(suppressMessages(install.packages("patchwork", verbose=TRUE, quiet=TRUE)))
suppressPackageStartupMessages(library(patchwork))
# Install and load the 'png' package
suppressWarnings(suppressMessages(install.packages("png", verbose=TRUE, quiet=TRUE)))
suppressPackageStartupMessages(library(png))
# Read datasets from the files
# Read the 'trees' data set
trees <- readr::read_csv('data/trees.csv', show_col_types = FALSE) %>%
mutate(spc_common = str_to_sentence(spc_common))
# Read the 'neighborhoods' data set
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"))
# ----- For link's image thumbnail
# Create a data
data <- data.frame(x = 1:3,
y = 1:3)
# Read the PNG file
my_image <- readPNG("documentation/pexels-photo-5031129.png", native = TRUE)
# Create a plot and combine with the image
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.5,
bottom = -0.5,
right = 1.5,
top = 1.5)# ---------- 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 the neighborhoods map
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")
defaultW <- getOption("warn")
options(warn=-1)
# 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)
tree_locs_map_plot
options(warn = defaultW)Tree Counts by Neighborhood:
In terms of the number of trees, the top ten neighborhoods are:
- *Upper West Side (MN12)
- Upper East Side-Carnegie Hill (MN40)
- *West Village (MN23)
- *Central Harlem North-Polo Grounds (MN03)
- *Hudson Yards-Chelsea-Flatiron-Union Square (MN13)
- *Washington Heights South (MN36)
- Morningside Heights (MN09)
- Central Harlem South (MN11)
- *Washington Heights North (MN35)
- *East Harlem North (MN34)
Seven of which (indicated by *) are part of the ten largest.
1 hidden cell
Trees by Curb Location:
Majority or
Trees' Curb Location by Neigborhood:
Twenty neighborhoods have at least
- East Village (MN22)
- Manhattanville (MN06)
- Gramercy (MN21)
- West Village (MN23)
- Hudson Yards-Chelsea-Flatiron-Union Square (MN13)
- Yorkville (MN32)
- Clinton (MN15)
- Washington Heights North (MN35)
- Lenox Hill-Roosevelt Island (MN31)
- 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:
- Stuyvesant Town-Cooper Village (MN50)
- Battery Park City-Lower Manhattan (MN25)
- Chinatown (MN27)
- Morningside Heights (MN09)
- East Harlem South (MN33)
- Lower East Side (MN28)
- SoHo-TriBeCa-Civic Center-Little Italy (MN24)
- Upper West Side (MN12)
- Lincoln Square (MN14)
- Upper East Side-Carnegie Hill (MN40)
1 hidden cell
Biological
Size: In terms of trunk diameter, the mean size of the tree population (red line in Fig. 5) is
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.