library(tidyverse)
library(sf)
library(sp)
library(tmap)
library(osmdata)
library(ggmap)
library(readxl)
library(classInt)
library(cowplot)
library(maps)
library(ggspatial)
library(ggthemes)
library(leaflet)
library(leaflet.esri)
Map centered on your neighborhood!
pdx_boundaries <- st_read("data/Neighborhoods__Regions_-shp")
## Reading layer `Neighborhoods__Regions_' from data source `/cloud/project/data/Neighborhoods__Regions_-shp' using driver `ESRI Shapefile'
## Simple feature collection with 98 features and 10 fields
## geometry type: MULTIPOLYGON
## dimension: XY
## bbox: xmin: -13677560 ymin: 5689875 xmax: -13632920 ymax: 5724919
## CRS: 3857
river_boundaries <- st_read("data/Willamette_Columbia_River_Ordinary_High_Water-shp/")
## Reading layer `Willamette_Columbia_River_Ordinary_High_Water' from data source `/cloud/project/data/Willamette_Columbia_River_Ordinary_High_Water-shp' using driver `ESRI Shapefile'
## Simple feature collection with 1 feature and 5 fields
## geometry type: MULTIPOLYGON
## dimension: XY
## bbox: xmin: -13676470 ymin: 5686111 xmax: -13632810 ymax: 5727803
## CRS: 3857
Multnomah <- pdx_boundaries %>% arrange(-Shape_Area) %>% filter(MAPLABEL=='Multnomah')
pdx_boundaries %>% ggplot() + geom_sf() +
coord_sf(
xlim=c( -13665229,-13657000),
ylim=c(5690426, 5698669)) +
geom_sf_label(aes(label=MAPLABEL))
pdx_boundaries %>% ggplot() + geom_sf(fill='navajowhite3') +
geom_sf(data=river_boundaries, fill="turquoise3", size=0.0)+
coord_sf(
xlim=c( -13664656,-13652123),
ylim=c(5689075, 5699953))+
theme_economist()+
geom_sf_label(data=Multnomah, aes(label=MAPLABEL))
Experiment with projections!
world1 <- sf::st_as_sf(map('world', plot = FALSE, fill = TRUE))
world2 <- sf::st_transform(
world1,
"+proj=laea +y_0=0 +lon_0=30.3609 +lat_0=59.9311 +ellps=WGS84 +no_defs"
)
ggplot() + geom_sf(data = world2)
world2 <- sf::st_transform(
world1,
"+proj=laea +y_0=0 +lon_0=-70.2568 +lat_0=43.659 +ellps=WGS84 +no_defs"
)
ggplot() + geom_sf(data = world2)
Plot both grocery stores and farmers markets!
trees_shape <- st_read("data/Parks_Tree_Inventory-shp")
## Reading layer `fd3ad191-4bf0-4577-b6ec-724baeb619792020413-1-a3eocm.isio' from data source `/cloud/project/data/Parks_Tree_Inventory-shp' using driver `ESRI Shapefile'
## Simple feature collection with 25534 features and 39 fields
## geometry type: POINT
## dimension: XY
## bbox: xmin: -13667450 ymin: 5692149 xmax: -13635010 ymax: 5724486
## CRS: 3857
farmers_market <- st_read("data/Farmers_Markets-shp/")
## Reading layer `Farmers_Markets' from data source `/cloud/project/data/Farmers_Markets-shp' using driver `ESRI Shapefile'
## Simple feature collection with 20 features and 11 fields
## geometry type: POINT
## dimension: XY
## bbox: xmin: -13665000 ymin: 5696460 xmax: -13644270 ymax: 5714893
## CRS: 3857
grocery_stores <- st_read("data/Grocery_Stores-shp/")
## Reading layer `Grocery_Stores' from data source `/cloud/project/data/Grocery_Stores-shp' using driver `ESRI Shapefile'
## Simple feature collection with 123 features and 9 fields
## geometry type: POINT
## dimension: XY
## bbox: xmin: -13665520 ymin: 5686206 xmax: -13634020 ymax: 5718088
## CRS: 3857
pdx_boundaries %>% ggplot() + geom_sf(fill='palegoldenrod') +
geom_sf(data=river_boundaries, fill="turquoise3", size=0.0)+
geom_sf(data=farmers_market, mapping=aes(color=Day))+
coord_sf(
xlim=c( -13664656,-13652123),
ylim=c(5689075, 5699953))+
geom_sf_label(data=Multnomah, aes(label=MAPLABEL))+
ggtitle("Farmer's Markets near Multnomah by Day")+
theme_economist()
pdx_boundaries %>% ggplot() +
geom_sf(fill='palegoldenrod') +
geom_sf(data=river_boundaries, fill="turquoise3", size=0.0)+
geom_sf(data=grocery_stores, mapping=aes(shape=STATUS, color=TYPE ))+
coord_sf(
xlim=c( -13664656,-13652123),
ylim=c(5689075, 5699953))+
geom_sf_label(data=Multnomah, aes(label=MAPLABEL))+
ggtitle("Grocery Stores near Multnomah by Type and Status")+
theme_economist()
Plot your neighborhood’s park
nrow(trees_shape)
## [1] 25534
pdx_boundaries %>% ggplot() + geom_sf() +
geom_sf(data=river_boundaries, fill="blue", size=0.0) +
geom_sf(data=trees_shape)
#Exploring trees
trees_raw <- read_csv("data/Parks_Tree_Inventory.csv")
## Parsed with column specification:
## cols(
## .default = col_character(),
## X = col_double(),
## Y = col_double(),
## OBJECTID = col_double(),
## DBH = col_double(),
## TreeHeight = col_double(),
## CrownWidthNS = col_double(),
## CrownWidthEW = col_double(),
## CrownBaseHeight = col_double(),
## UserID = col_double(),
## Structural_Value = col_double(),
## Carbon_Storage_lb = col_double(),
## Carbon_Storage_value = col_double(),
## Carbon_Sequestration_lb = col_double(),
## Carbon_Sequestration_value = col_double(),
## Stormwater_ft = col_double(),
## Stormwater_value = col_double(),
## Pollution_Removal_value = col_double(),
## Pollution_Removal_oz = col_double(),
## Total_Annual_Benefits = col_double()
## )
## See spec(...) for full column specifications.
glimpse(trees_raw)
## Observations: 25,534
## Variables: 41
## $ X <dbl> -13658194, -13658213, -13658254, -13658227…
## $ Y <dbl> 5712487, 5712485, 5712491, 5712487, 571248…
## $ OBJECTID <dbl> 426, 427, 428, 429, 430, 431, 432, 433, 43…
## $ Inventory_Date <chr> "2017/05/09 00:00:00+00", "2017/05/09 00:0…
## $ Species <chr> "PSME", "PSME", "CRLA", "QURU", "PSME", "P…
## $ DBH <dbl> 37.4, 32.5, 9.7, 10.3, 33.2, 32.1, 28.4, 2…
## $ Condition <chr> "Fair", "Fair", "Fair", "Poor", "Fair", "F…
## $ TreeHeight <dbl> 105, 94, 23, 28, 102, 95, 103, 105, 97, 11…
## $ CrownWidthNS <dbl> 44, 49, 28, 38, 43, 35, 40, 45, 56, 35, 45…
## $ CrownWidthEW <dbl> 57, 45, 27, 31, 44, 39, 40, 29, 45, 33, 50…
## $ CollectedBy <chr> "staff", "staff", "staff", "staff", "staff…
## $ Notes <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ CrownBaseHeight <dbl> 4, 4, 3, 5, 4, 12, 6, 13, 5, 17, 6, 6, 4, …
## $ GlobalID <chr> "{8413C6D7-038A-4685-AFCB-C3BCE4D90A24}", …
## $ StaffReview <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ created_user <chr> "PARKS_ADMIN", "PARKS_ADMIN", "PARKS_ADMIN…
## $ created_date <chr> "2017/05/23 19:37:43+00", "2017/05/23 19:3…
## $ last_edited_user <chr> "PKJOSHUA", "PKJOSHUA", "PKJOSHUA", "PKJOS…
## $ last_edited_date <chr> "2019/12/11 00:42:17+00", "2019/12/11 00:4…
## $ UserID <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,…
## $ Structural_Value <dbl> 10101.06, 7900.55, 1110.81, 525.26, 8224.5…
## $ Carbon_Storage_lb <dbl> 3223.3, 2460.8, 310.3, 400.1, 2533.4, 2333…
## $ Carbon_Storage_value <dbl> 209.07, 159.62, 20.13, 25.95, 164.33, 151.…
## $ Carbon_Sequestration_lb <dbl> 36.8, 31.3, 14.8, 6.0, 32.0, 30.8, 26.8, 2…
## $ Carbon_Sequestration_value <dbl> 2.39, 2.03, 0.96, 0.39, 2.08, 2.00, 1.74, …
## $ Stormwater_ft <dbl> 150.3, 133.0, 35.4, 38.3, 115.5, 85.3, 99.…
## $ Stormwater_value <dbl> 10.05, 8.89, 2.37, 2.56, 7.72, 5.70, 6.66,…
## $ Pollution_Removal_value <dbl> 18.25, 16.15, 4.31, 4.65, 14.03, 10.36, 12…
## $ Pollution_Removal_oz <dbl> 40.4, 35.8, 9.5, 10.3, 31.1, 22.9, 26.8, 2…
## $ Total_Annual_Benefits <dbl> 30.69, 27.06, 7.64, 7.59, 23.82, 18.06, 20…
## $ Family <chr> "Pinaceae", "Pinaceae", "Rosaceae", "Fagac…
## $ Genus <chr> "Pseudotsuga", "Pseudotsuga", "Crataegus",…
## $ Common_name <chr> "Douglas-fir", "Douglas-fir", "Lavalle haw…
## $ Genus_species <chr> "Pseudotsuga menziesii", "Pseudotsuga menz…
## $ Functional_type <chr> "CE", "CE", "BD", "BD", "CE", "CE", "CE", …
## $ Size <chr> "L", "L", "S", "L", "L", "L", "L", "L", "L…
## $ Native <chr> "Yes", "Yes", "No", "No", "Yes", "Yes", "Y…
## $ Edible <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ Nuisance <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ Origin <chr> "North America - from British Columbia sou…
## $ Species_factoid <chr> "Bracts on cones look like a mouse's feet …
trees_raw %>% ggplot(mapping=aes(x=TreeHeight)) + geom_histogram(bins=50) + ggtitle("Histogram of park tree height")
## Warning: Removed 1 rows containing non-finite values (stat_bin).
pdx_boundaries %>% ggplot() +
geom_sf() +
stat_density_2d(data=trees_raw, aes(X, Y))+
geom_sf(data=river_boundaries, fill="blue", size=0.0)
# Converting coordinates for the park
p3 <- data.frame(lon=c(-122.675, -122.665), lat=c(45.48, 45.47))
sf_project(
sf::st_crs(4326), # to: default datum used by geom_sf
sf::st_crs(3857), # from: datum used by Portland Maps data
p3
)
## [,1] [,2]
## [1,] -13656119 5697407
## [2,] -13655005 5695819
pdx_boundaries %>% ggplot() +
geom_sf(fill='palegoldenrod') +
geom_sf(data=river_boundaries, fill="blue", size=0.0) +
geom_sf(data=trees_shape) +
coord_sf(xlim=c( -13656119, -13655005), ylim=c(5695819, 5697407))+
ggtitle("Wilamette Park")+
theme_economist()
# Count of trees in the park
trees_in_park <- st_crop(trees_shape, xmin=-13656119, ymin=5695819, xmax=-13655005, ymax=5697407)
## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries
paste0("Total number of trees in original dataset: ", length(trees_shape$geometry))
## [1] "Total number of trees in original dataset: 25534"
paste0("Number of trees in our bounding box: ", length(trees_in_park$geometry))
## [1] "Number of trees in our bounding box: 370"
Use OpenStreetMap tiles
park_base_map <- get_stamenmap(
c(left=-122.674, bottom=45.47, right=-122.666, top=45.48), zoom=16, maptype="terrain")
## Source : http://tile.stamen.com/terrain/16/10435/23450.png
## Source : http://tile.stamen.com/terrain/16/10436/23450.png
## Source : http://tile.stamen.com/terrain/16/10437/23450.png
## Source : http://tile.stamen.com/terrain/16/10435/23451.png
## Source : http://tile.stamen.com/terrain/16/10436/23451.png
## Source : http://tile.stamen.com/terrain/16/10437/23451.png
## Source : http://tile.stamen.com/terrain/16/10435/23452.png
## Source : http://tile.stamen.com/terrain/16/10436/23452.png
## Source : http://tile.stamen.com/terrain/16/10437/23452.png
## Source : http://tile.stamen.com/terrain/16/10435/23453.png
## Source : http://tile.stamen.com/terrain/16/10436/23453.png
## Source : http://tile.stamen.com/terrain/16/10437/23453.png
ggmap(park_base_map)+
ggtitle("Wilamette Park")
park_base_map <- get_stamenmap(
c(left=-122.674, bottom=45.47, right=-122.666, top=45.48), zoom=16, maptype="watercolor")
## Source : http://tile.stamen.com/watercolor/16/10435/23450.jpg
## Source : http://tile.stamen.com/watercolor/16/10436/23450.jpg
## Source : http://tile.stamen.com/watercolor/16/10437/23450.jpg
## Source : http://tile.stamen.com/watercolor/16/10435/23451.jpg
## Source : http://tile.stamen.com/watercolor/16/10436/23451.jpg
## Source : http://tile.stamen.com/watercolor/16/10437/23451.jpg
## Source : http://tile.stamen.com/watercolor/16/10435/23452.jpg
## Source : http://tile.stamen.com/watercolor/16/10436/23452.jpg
## Source : http://tile.stamen.com/watercolor/16/10437/23452.jpg
## Source : http://tile.stamen.com/watercolor/16/10435/23453.jpg
## Source : http://tile.stamen.com/watercolor/16/10436/23453.jpg
## Source : http://tile.stamen.com/watercolor/16/10437/23453.jpg
ggmap(park_base_map)+
ggtitle("Wilamette Park")
# Adding trees
trees_park_projected <- st_transform(trees_in_park, sf::st_crs(4326))
ggmap(park_base_map) +
ggtitle("Wilamette Park")+
geom_sf(data=trees_park_projected, inherit.aes = FALSE)
## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
#Coloring the trees and changing color option on the map
park_base_map <- get_stamenmap(
c(left=-122.674, bottom=45.47, right=-122.666, top=45.48), zoom=16, maptype="terrain")
ggmap(park_base_map) +
ggtitle("Wilamette Park")+
geom_sf(data=trees_park_projected, inherit.aes = FALSE,
alpha=0.05,
mapping=aes(color=Condition))
## Coordinate system already present. Adding new coordinate system, which will replace the existing one.
# making a hybrid map
leaflet(trees_park_projected) %>% # we can pass in a dataframe to use...
addEsriBasemapLayer(esriBasemapLayers$Imagery) %>%
setView(-122.670, 45.475, zoom=16) %>%
addCircleMarkers(label = ~Condition)
A map using a different census column (or multiple columns!)
pdx_lonesome <- read_excel("data/new_census.xlsx",
sheet="Census_2010_Neighborhoods",
range="A7:D101",
col_names = c("Neighborhood", "Total.Pop", "MaleAlone", "FemaleAlone")) %>% mutate(Neighborhood=as.factor(Neighborhood))
pdx_lonesome <- pdx_lonesome %>% mutate(Neighborhood=recode(Neighborhood,
"ARGAY" = "ARGAY TERRACE",
"BROOKLYN" = "BROOKLYN ACTION CORPS",
"BUCKMAN" = "BUCKMAN COMMUNITY ASSOCIATION",
"CENTENNIAL" = "CENTENNIAL COMMUNITY ASSOCIATION",
"CULLY" = "CULLY ASSOCIATION OF NEIGHBORS",
"CENTENNIAL" = "CENTENNIAL COMMUNITY ASSOCIATION",
"DOWNTOWN" = "PORTLAND DOWNTOWN",
"GOOSE HOLLOW" = "GOOSE HOLLOW FOOTHILLS LEAGUE",
"HAYDEN ISLAND" = "HAYDEN ISLAND NEIGHBORHOOD NETWORK",
"HOSFORD-ABERNETHY" = "HOSFORD-ABERNETHY NEIGHBORHOOD DISTRICT ASSN.",
"IRVINGTON" = "IRVINGTON COMMUNITY ASSOCIATION",
"LLOYD DISTRICT" = "LLOYD DISTRICT COMMUNITY ASSOCIATION",
"NORTHWEST DISTRICT" = "NORTHWEST DISTRICT ASSOCIATION",
"OLD TOWN-CHINATOWN" = "OLD TOWN COMMUNITY ASSOCIATION",
"PARKROSE HEIGHTS" = "PARKROSE HEIGHTS ASSOCIATION OF NEIGHBORS",
"PEARL" = "PEARL DISTRICT",
"SABIN" = "SABIN COMMUNITY ASSOCIATION",
"SELLWOOD-MORELAND" = "SELLWOOD-MORELAND IMPROVEMENT LEAGUE",
"SOUTHWEST HILLS" = "SOUTHWEST HILLS RESIDENTIAL LEAGUE",
"SUMNER" = "SUMNER ASSOCIATION OF NEIGHBORS",
"SUNDERLAND" = "SUNDERLAND ASSOCIATION OF NEIGHBORS",
"WILKES" = "WILKES COMMUNITY GROUP"
))
boundaries_with_lonesome <- left_join(pdx_boundaries, pdx_lonesome, by=c("NAME"="Neighborhood"))
## Warning: Column `NAME`/`Neighborhood` joining factors with different levels,
## coercing to character vector
boundaries_with_lonesome_males <- boundaries_with_lonesome %>%
mutate(adj_male_pop = (MaleAlone / (Shape_Area / 1E6))) %>% arrange(adj_male_pop)
boundaries_with_lonesome_males %>% ggplot() +
geom_sf(aes(fill=adj_male_pop)) +
scale_fill_gradient() +
geom_sf(data=river_boundaries, fill="turquoise3", size=0.0)+
ggtitle("Neighborhoods with high concentration males living alone")
boundaries_with_lonesome_females <-boundaries_with_lonesome %>%
mutate(adj_fem_pop = (FemaleAlone / (Shape_Area / 1E6))) %>% arrange(adj_fem_pop)
boundaries_with_lonesome_females %>% ggplot() +
geom_sf(aes(fill=adj_fem_pop)) +
scale_fill_gradient() +
geom_sf(data=river_boundaries, fill="turquoise3", size=0.0)+
ggtitle("Neighborhoods with high concentration females living alone")
boundaries_with_lonesome_females %>% ggplot(mapping=aes(x=adj_fem_pop))+
geom_histogram(bins=50) +
ggtitle("Histogram of lonesome females")
## Warning: Removed 4 rows containing non-finite values (stat_bin).
min.pop <- min(boundaries_with_lonesome_females$adj_fem_pop, na.rm=TRUE)
max.pop <- max(boundaries_with_lonesome_females$adj_fem_pop, na.rm=TRUE)
diff.pop <- max.pop - min.pop
std.dev.pop <- sd(boundaries_with_lonesome_females$adj_fem_pop, na.rm = TRUE)
# some possible color break points
equal.interval <- seq(min.pop, max.pop, by= diff.pop / 4)
quantile.interval <- quantile(boundaries_with_lonesome_females$adj_fem_pop, probs=seq(0, 1, by = 1/4), na.rm = TRUE)
std.interval <- c(seq(min.pop, max.pop, by=std.dev.pop), max.pop)
jenks.interval <- classIntervals(boundaries_with_lonesome_females$adj_fem_pop, n=6, style='jenks')$brks
## Warning in classIntervals(boundaries_with_lonesome_females$adj_fem_pop, : var
## has missing values, omitted in finding classes
boundaries_with_lonesome_females$pop.equal = cut(boundaries_with_lonesome_females$adj_fem_pop, breaks=equal.interval, include.lowest = TRUE)
boundaries_with_lonesome_females$pop.quantile = cut(boundaries_with_lonesome_females$adj_fem_pop, breaks=quantile.interval, include.lowest = TRUE)
boundaries_with_lonesome_females$pop.std = cut(boundaries_with_lonesome_females$adj_fem_pop, breaks=std.interval, include.lowest = TRUE)
boundaries_with_lonesome_females$pop.jenks = cut(boundaries_with_lonesome_females$adj_fem_pop, breaks=jenks.interval, include.lowest = TRUE)
popDensBarChart <- function(break_col) {
boundaries_with_lonesome_females %>%
filter(!is.na(adj_fem_pop)) %>%
ggplot(mapping = aes(x=fct_reorder(MAPLABEL, -adj_fem_pop), y=adj_fem_pop)) +
geom_col(aes(fill=.data[[break_col]])) +
# theme(axis.text.x=element_text(angle=270, hjust=0, size=6, vjust=0.5)) +
theme(axis.text.x=element_blank(), axis.ticks.x=element_blank()) +
scale_y_continuous(name=expression("People/km" ^2)) +
scale_x_discrete(name=NULL) +
scale_fill_discrete(guide=FALSE) +
ggtitle(break_col)
}
plot_grid(
popDensBarChart("pop.equal"),
popDensBarChart("pop.quantile"),
popDensBarChart("pop.std"),
popDensBarChart("pop.jenks"),
nrow=2, ncol=2
)
# Final graphs
pop.plot <- function(col){
boundaries_with_lonesome_females %>%
ggplot()+
geom_sf(aes(fill=.data[[col]]))+
scale_fill_brewer(palette="YlOrBr", name=expression("people/km" ^2))+
geom_sf(data=river_boundaries, fill='turquoise3', size=0.0)+
ggtitle(col)
}
pop.plot('pop.equal')
pop.plot("pop.quantile")
pop.plot("pop.std")
pop.plot("pop.jenks")