library(dplyr)
library(sfext)
library(getdata)
# Set state FIPS for Maryland
state_fips <- 24
# Set county FIPS for Baltimore City
county_fips <- 510
# Set name for Baltimore City
county_name <- "Baltimore City"
# Set projected CRS (NAD83(HARN) / Maryland, meters)
selected_crs <- 2804
# Nested CSAs are used to download larger datasets in portions
csas_nest <- csas %>%
dplyr::nest_by(name)
balt_tbl_labs <-
googlesheets4::read_sheet("https://docs.google.com/spreadsheets/d/1FXEJlhccnhoQmSO2WydBidXIw-f2lpomURDGy9KBgJw/edit?usp=sharing")
usethis::use_data(balt_tbl_labs, overwrite = TRUE)
md_counties <- getdata::get_tigris_data(type = "counties", state = state_fips, crs = selected_crs, cb = FALSE)
baltimore_msa_counties <- md_counties %>%
dplyr::filter(name %in% c("Baltimore", "Anne Arundel", "Carroll", "Harford", "Howard", "Queen Anne's"))
usethis::use_data(baltimore_msa_counties, overwrite = TRUE)
# Download generalized city boundary
baltimore_city <- tigris::county_subdivisions(state = state_fips, county = county_fips) %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake") %>%
dplyr::select(
name = namelsad,
countyfp,
geoid,
aland,
awater,
intptlat,
intptlon
)
usethis::use_data(baltimore_city, overwrite = TRUE)
baltimore_bbox <- sfext::as_bbox(baltimore_city, 4326)
usethis::use_data(baltimore_bbox, overwrite = TRUE)
## Import detailed Baltimore City boundary from ArcGIS FeatureServer layer
maryland_counties_detailed_path <- "https://geodata.md.gov/imap/rest/services/Boundaries/MD_PhysicalBoundaries/FeatureServer/0"
maryland_counties_detailed <- esri2sf::esri2sf(maryland_counties_detailed_path) %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake")
baltimore_city_detailed <- maryland_counties_detailed %>%
dplyr::filter(county == county_name) %>%
dplyr::select(
name = county,
countyfp = county_fip,
geometry = geoms
)
usethis::use_data(baltimore_city_detailed, overwrite = TRUE)
## Import Baltimore City Council Districts from ArcGIS MapServer layer
council_districts_path <- "https://geodata.baltimorecity.gov/egis/rest/services/CityView/City_Council_Districts/MapServer/0"
council_districts <- esri2sf::esri2sf(council_districts_path) %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake") %>%
dplyr::select(
id = area_name,
geometry = geoms
) %>%
dplyr::mutate(
id = as.character(id),
name = paste0("District ", id)
)
usethis::use_data(council_districts, overwrite = TRUE)
## Baltimore City Legislative Districts ----
# Import legislative districts from ArcGIS FeatureServer layer
# 2022
legislative_districts <-
getdata::get_esri_data(
url = "https://geodata.md.gov/imap/rest/services/Boundaries/MD_ElectionBoundaries_2022/FeatureServer/1",
location = mapbaltimore::baltimore_city,
crs = 2804
)
legislative_districts <-
legislative_districts %>%
sfext::st_filter_ext(mapbaltimore::baltimore_city %>%
sfext::st_buffer_ext(dist = -1000, unit = "m")) %>%
rename_sf_col() %>%
select(id = district) %>%
mutate(
name = paste0("District ", id),
label = paste0("Maryland House of Delegates ", name)
) %>%
arrange(id)
use_data(legislative_districts, overwrite = TRUE)
# 2012
baltimore_city_legislative_districts <- c("40", "41", "43", "44A", "45", "46")
legislative_districts_2012_path <- "https://geodata.md.gov/imap/rest/services/Boundaries/MD_ElectionBoundaries/FeatureServer/1"
legislative_districts_2012 <- esri2sf::esri2sf(legislative_districts_2012_path) %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake") %>%
dplyr::select(
name = district,
geometry = geoms
) %>%
dplyr::mutate(
id = name,
name = paste0("District ", name),
label = paste0("Maryland House of Delegates ", name)
) %>%
# Filter to Baltimore City districts
dplyr::filter(id %in% baltimore_city_legislative_districts) %>%
dplyr::arrange(id)
usethis::use_data(legislative_districts_2012, overwrite = TRUE)
## U.S. Congressional Districts ----
# Import congressional districts
md_congressional_districts <- tigris::congressional_districts() %>%
dplyr::filter(STATEFP == state_fips)
congressional_district_names <- tibble::tribble(
~CD116FP, ~label, ~name,
"02", "Maryland's 2nd congressional district", "2nd District",
"03", "Maryland's 3rd congressional district", "3rd District",
"07", "Maryland's 7th congressional district", "7th District"
)
congressional_districts <- md_congressional_districts %>%
sf::st_transform(selected_crs) %>%
sf::st_join(baltimore_city) %>%
dplyr::filter(!is.na(name)) %>%
dplyr::select(-c(name:intptlon)) %>%
dplyr::left_join(congressional_district_names, by = "CD116FP") %>%
janitor::clean_names("snake")
usethis::use_data(congressional_districts, overwrite = TRUE)
planning_districts_path <- "https://geodata.baltimorecity.gov/egis/rest/services/Housing/dmxBoundaries3/MapServer/9"
planning_districts <- esri2sf::esri2sf(planning_districts_path) %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake") %>%
dplyr::mutate(
name = paste0(area_name, " Planning District")
) %>%
dplyr::select(
id = area_name,
name,
abb = area_abbr,
geometry = geoms
) %>%
dplyr::arrange(id)
planning_districts <- planning_districts %>%
sf::st_make_valid() %>%
st_trim(mapbaltimore::baltimore_city) %>%
sf::st_cast("MULTIPOLYGON")
usethis::use_data(planning_districts, overwrite = TRUE)
neighborhoods_2020_path <- "https://services1.arcgis.com/43Lm3JYE3nM91DAF/arcgis/rest/services/NSA_March2023/FeatureServer/0"
neighborhoods_2020_source <- neighborhoods_2020_path |>
esri2sf::esri2sf(crs = selected_crs) %>%
sfext::rename_sf_col()
neighborhoods_2020 <- neighborhoods_2020_source |>
janitor::clean_names("snake") %>%
dplyr::mutate(
acres = as.numeric(units::set_units(sf::st_area(geometry), "acres")),
type = dplyr::case_when(
(stringr::str_detect(name, "Industrial") | name == "Jones Falls Area" | name == "Dundalk Marine Terminal") ~ "Industrial area",
stringr::str_detect(name, "Business Park") ~ "Business park",
name %in% c("University Of Maryland", "Morgan State University") ~ "Institutional area",
# NOTE: This classifies Montebello as a park but is more accurately described as a reservoir
name %in% c(
"Gwynns Falls/Leakin Park", "Druid Hill Park", "Patterson Park", "Clifton Park", "Carroll Park",
"Montebello", "Greenmount Cemetery", "Herring Run Park", "Lower Herring Run Park"
) ~ "Park/open space",
TRUE ~ "Residential"
)
) %>%
dplyr::select(
name,
type,
acres,
color_id = color_2,
geometry
) %>%
dplyr::mutate(
name_alt = case_match(
name,
"Perkins" ~ "Perkins Homes",
"Mount Clare" ~ "New Southwest/Mount Clare",
"Stadium/Entertainment Area" ~ "Stadium Area",
"Baltimore Peninsula" ~ "Port Covington",
"Fairmount" ~ "Fairmont",
"Butchers Hill" ~ "Butcher's Hill",
"Villages of Homeland" ~ "Villages Of Homeland",
"Auchentoroly-Parkwood" ~ "Parkview/Woodbrook",
"Parkway" ~ "Burleith-Leighton",
# "Chinquapin Park" ~ "Wrenlane",
"Concerned Citizens of Forest Park" ~ "Concerned Citizens Of Forest Park",
"Carroll - Camden Industrial Area" ~ name,
"University Of Maryland" ~ name,
"Four By Four" ~ name,
.default = NA_character_
),
name_join = coalesce(name_alt, name),
.after = name
) |>
dplyr::mutate(
name = case_match(name,
"University Of Maryland" ~ "University of Maryland",
"Four By Four" ~ "Four by Four",
"Carroll - Camden Industrial Area" ~ "Carroll-Camden Industrial Area",
.default = name)
) |>
dplyr::left_join(
mapbaltimore::neighborhoods |>
sf::st_drop_geometry() |>
dplyr::select(
osm_id,
wikidata,
name_join = name
),
by = "name_join"
) |>
dplyr::relocate(
color_id,
.after = "wikidata"
) |>
dplyr::select(!name_join) |>
dplyr::arrange(name)
usethis::use_data(neighborhoods_2020, overwrite = TRUE)
# Import neighborhood boundaries from iMAP (derived from a data set previously available on Open Baltimore)
# https://opendata.maryland.gov/Society/MD-iMAP-Maryland-Baltimore-City-Neighborhoods/dbbp-8u4u
neighborhoods_2010_path <- "https://opendata.arcgis.com/datasets/fc5d183b20a145009eae8f8b171eeb0d_0.geojson"
neighborhoods_2010 <- sf::read_sf(neighborhoods_path) %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake") %>%
dplyr::rename(name = label) %>%
dplyr::mutate(
acres = as.numeric(units::set_units(sf::st_area(geometry), "acres")),
type = dplyr::case_when(
(stringr::str_detect(name, "Industrial") | name == "Jones Falls Area" | name == "Dundalk Marine Terminal") ~ "Industrial area",
stringr::str_detect(name, "Business Park") ~ "Business park",
name %in% c("University Of Maryland", "Morgan State University") ~ "Institutional area",
# NOTE: This classifies Montebello as a park but is more accurately described as a reservoir
name %in% c(
"Gwynns Falls/Leakin Park", "Druid Hill Park", "Patterson Park", "Clifton Park", "Carroll Park",
"Montebello", "Greenmount Cemetery", "Herring Run Park", "Lower Herring Run Park"
) ~ "Park/open space",
TRUE ~ "Residential"
)
) %>%
dplyr::select(
name,
type,
acres,
geometry
) %>%
dplyr::arrange(name)
osm_nhoods <-
get_area_osm_data(
area = baltimore_city,
key = "place",
value = "neighbourhood",
return_type = "osm_multipolygons"
) %>%
sf::st_drop_geometry() %>%
dplyr::select(name, osm_id, wikidata)
osm_nhoods <- osm_nhoods %>%
dplyr::mutate(
name =
dplyr::case_when(
name == "Fell's Point" ~ "Fells Point",
name == "Upper Fell's Point" ~ "Upper Fells Point",
name == "Four by Four" ~ "Four By Four",
name == "Butchers Hill" ~ "Butcher's Hill",
name == "Old Town" ~ "Oldtown",
name == "Coldstream-Homestead-Montebello" ~ "Coldstream Homestead Montebello",
name == "Gwynn's Falls" ~ "Gwynns Falls",
name == "Patterson Park" ~ "Patterson Park Neighborhood",
TRUE ~ name
)
) %>%
naniar::replace_with_na(list(wikidata = ""))
neighborhoods <- neighborhoods %>%
dplyr::left_join(osm_nhoods, by = "name") %>%
dplyr::relocate(geometry, .after = "wikidata")
usethis::use_data(neighborhoods, overwrite = TRUE)
neighborhoods <- esri2sf::esri2sf(
"https://services1.arcgis.com/43Lm3JYE3nM91DAF/ArcGIS/rest/services/NSA_March2023/FeatureServer/0"
)
neighborhoods_2010 <- mapbaltimore::neighborhoods
# dplyr::left_join(neighborhoods, sf::st_drop_geometry(neighborhoods_2010), by = c("LABEL" = "name")) |>
# View()
# Import Community Statistical Area boundaries from University of Baltimore BNIA-JFI ArcGIS FeatureServer layer
csas_path <- "https://services1.arcgis.com/mVFRs7NF4iFitgbY/arcgis/rest/services/Community_Statistical_Areas_(CSAs)__Reference_Boundaries/FeatureServer/0"
csas <- esri2sf::esri2sf(csas_path) %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake") %>%
dplyr::mutate(
neigh = strsplit(neigh, ","),
tracts = strsplit(tracts, ","),
) %>%
dplyr::select(
id = fid,
name = community,
# Exclude list of neighborhoods and tracts. See xwalk files from baltimoredata package
# neighborhoods = neigh,
# tracts,
url = link,
geometry = geoms
) %>%
dplyr::mutate(
# Internally inconsistent naming for CSAs retained to maintain consistency with official names
# name = case_when(
# name == "Allendale/Irvington/S. Hilton" ~ "Allendale/Irvington/South Hilton",
# TRUE ~ name
# ),
url = stringr::str_replace(url, "http://", "https://")
) %>%
dplyr::arrange(id)
usethis::use_data(csas, overwrite = TRUE)
# Crosswalk: Community Statistical Areas to Zip Codes ----
xwalk_zip2csa <- rio::import(
file = "https://bniajfi.org/wp-content/uploads/2014/04/Zip-to-CSA-2010.xls",
setclass = "tibble",
col_types = "text"
) %>%
dplyr::rename(zip = Zip2010, csa = CSA2010) %>%
dplyr::mutate(
csa = dplyr::case_when(
csa == "Orangeville/E. Highlandtown" ~ "Orangeville/East Highlandtown",
csa == "Howard Park/W. Arlington" ~ "Howard Park/West Arlington",
csa == "Cross Country/Cheswolde" ~ "Cross-Country/Cheswolde",
csa == "Mt. Washington/Coldspring" ~ "Mount Washington/Coldspring",
csa == "N. Baltimore/Guilford/Homeland" ~ "North Baltimore/Guilford/Homeland",
csa == "Westport/Mt. Winans/Lakeland" ~ "Westport/Mount Winans/Lakeland",
TRUE ~ csa
)
) %>%
dplyr::left_join(sf::st_drop_geometry(csas), by = c("csa" = "name"))
usethis::use_data(xwalk_zip2csa, overwrite = TRUE)
# Crosswalk: Community Statistical Areas to Neighborhood Statistical Areas ----
xwalk_csa2nsa <- rio::import(
file = "https://bniajfi.org/wp-content/uploads/2014/04/CSA-to-NSA-2010.xlsx",
setclass = "tibble",
col_types = "text"
) %>%
dplyr::rename(csa = CSA2010, nsa = NSA2010) %>%
# Add missing NSAs
dplyr::add_row(
csa = "Belair-Edison",
nsa = "Lower Herring Run Park"
) %>%
dplyr::add_row(
csa = "Southeastern",
nsa = "Broening Manor"
) %>%
dplyr::mutate(
# Fix CSA names to match csas
csa = dplyr::case_when(
csa == "Allendale/Irvington/South Hilton" ~ "Allendale/Irvington/S. Hilton",
csa == "Mt. Washington/Coldspring" ~ "Mount Washington/Coldspring",
csa == "Westport/Mt. Winans/Lakeland" ~ "Westport/Mount Winans/Lakeland",
csa == "Glen-Falstaff" ~ "Glen-Fallstaff",
TRUE ~ csa
),
# Fix NSA assigned to incorrect area
csa = dplyr::case_when(
nsa == "Spring Garden Industrial Area" ~ "South Baltimore",
TRUE ~ csa
),
# Add neighborhood column with names to match neighborhoods
neighborhood = dplyr::case_when(
nsa == "Booth-Boyd" ~ "Boyd-Booth",
nsa == "Caroll-Camden Industrial Area" ~ "Carroll - Camden Industrial Area",
nsa == "Glenham-Belford" ~ "Glenham-Belhar",
nsa == "North Harford Road" ~ "Hamilton Hills",
nsa == "Mt. Washington" ~ "Mount Washington",
nsa == "Mt. Winans" ~ "Mount Winans",
nsa == "Mt. Pleasant Park" ~ "Mt Pleasant Park",
nsa == "New Southwest/Mt. Clare" ~ "New Southwest/Mount Clare",
nsa == "Rosemont Homewoners/Tenants" ~ "Rosemont Homeowners/Tenants",
nsa == "University of Maryland" ~ "University Of Maryland",
TRUE ~ nsa
)
) %>%
dplyr::left_join(sf::st_drop_geometry(csas), by = c("csa" = "name")) %>%
dplyr::relocate(id, .before = csa)
usethis::use_data(xwalk_csa2nsa, overwrite = TRUE)
# Import Baltimore City Public School 2020-2021 attendance zones from ArcGIS Feature Server layer
bcps_zones_path <- "https://services3.arcgis.com/mbYrzb5fKcXcAMNi/ArcGIS/rest/services/SY2122_Ezones_and_Programs/FeatureServer/15"
bcps_zones <- esri2sf::esri2sf(bcps_zones_path, crs = selected_crs) %>%
janitor::clean_names("snake") %>%
dplyr::select(
# program_name = prog_name,
# program_number = prog_no,
zone_name,
program_number = zone_no,
geometry = geoms
) %>%
dplyr::left_join(
sf::st_drop_geometry(bcps_programs),
by = "program_number"
) %>%
dplyr::select(-swing_space) %>%
dplyr::arrange(program_number) %>%
sfext::relocate_sf_col()
usethis::use_data(bcps_zones, overwrite = TRUE)
# 2021-2022 program sites
bcps_programs_path <- "https://services3.arcgis.com/mbYrzb5fKcXcAMNi/ArcGIS/rest/services/SY2122_Ezones_and_Programs/FeatureServer/11"
bcps_programs <- esri2sf::esri2sf(bcps_programs_path, crs = 2804) %>%
janitor::clean_names("snake")
bcps_programs <- bcps_programs %>%
# sf::st_transform(selected_crs) %>%
dplyr::select(
program_name_short = prog_short,
program_number = prog_no,
type = mgmnt_type,
category = categorization,
# zone_name,
swing_space = swing,
geometry = geoms
) %>%
dplyr::mutate(
swing_space = if_else(
swing_space == "y", TRUE, FALSE
)
)
bcps_programs <- bcps_programs %>%
dplyr::arrange(program_number)
osm_schools <-
getdata::get_osm_data(
location = mapbaltimore::baltimore_city,
key = "amenity",
value = "school",
geometry = "polygons"
)
osm_schools_join <-
sf::st_join(
bcps_programs,
osm_schools %>% sf::st_transform(2804),
suffix = c("", "_osm")
)
bcps_programs <-
osm_schools_join %>%
select(
program_name_short,
program_number,
osm_name, # = name,
osm_id,
type,
category,
swing_space
) %>%
mutate(
osm_id = paste0("way/", osm_id)
)
bcps_programs <-
naniar::replace_with_na(bcps_programs, list(osm_id = "way/NA"))
usethis::use_data(bcps_programs, overwrite = TRUE)
# Download ward maps from KML files from Baltimore City Archives
# https://msa.maryland.gov/bca/wards/index.html
# wards_1797_1918_path <- "/baltimore-city-ward-maps" # Replace with path to folder w/ KML files
wards_1797_1918 <- fs::dir_ls(path = wards_1797_1918_path) %>%
tibble::tibble(filename = .) %>%
dplyr::mutate(
year = as.numeric(stringr::str_sub(filename, -8, -5)),
data = purrr::map(
filename,
~ sf::read_sf(.) %>%
sf::st_zm() %>%
sf::st_transform(selected_crs) %>%
dplyr::select(
name = Name,
geometry
) %>%
dplyr::mutate(number = as.numeric(stringr::str_extract(name, "[:digit:]+")))
)
) %>%
tidyr::unnest(data) %>%
dplyr::select(-filename) %>%
dplyr::arrange(year, number) %>%
sf::st_as_sf()
usethis::use_data(wards_1797_1918, overwrite = TRUE)
## Park districts ----
park_districts <- esri2sf::esri2sf("https://services1.arcgis.com/UWYHeuuJISiGmgXx/ArcGIS/rest/services/AGOL_BCRP_MGMT_20181220/FeatureServer/3")
park_districts <- park_districts %>%
dplyr::select(
name = AREA_NAME,
geometry = geoms
) %>%
sf::st_transform(selected_crs)
usethis::use_data(park_districts, overwrite = TRUE)
## Parks ----
# Set path to city parks hosted ArcGIS MapServer layer
# parks_path <- "https://services1.arcgis.com/UWYHeuuJISiGmgXx/ArcGIS/rest/services/Baltimore_City_Recreation_and_Parks/FeatureServer/2"
# parks_path <- "https://services1.arcgis.com/UWYHeuuJISiGmgXx/arcgis/rest/services/AGOL_BCRP_MGMT_20181220/FeatureServer/2"
# parks_path <- "https://services1.arcgis.com/UWYHeuuJISiGmgXx/arcgis/rest/services/AGOL_BCRP_Council_20190221_gdb/FeatureServer/0"
parks_path <- "https://services1.arcgis.com/UWYHeuuJISiGmgXx/arcgis/rest/services/Map_WFL1/FeatureServer/16"
# parks_path <- "https://services1.arcgis.com/UWYHeuuJISiGmgXx/arcgis/rest/services/rec_park_dgs_assets_projected/FeatureServer/0"
# Import parks data with esri2sf package
parks_bcrp <- getdata::get_esri_data(
url = parks_path,
crs = selected_crs # Transform to projected CRS
)
parks <- parks_bcrp %>%
sf::st_make_valid() %>% # Make valid to avoid "Ring Self-intersection" error
dplyr::rename(
operator_name = operator
) |>
dplyr::select(
name,
id = park_id,
address,
name_alt,
num_parcels = parcels,
operator = bcrp,
operator_name,
class,
geometry = geoms
) %>% # Select relevant columns
sf::st_join(dplyr::select(mapbaltimore::park_districts, park_district = name), largest = TRUE) %>%
dplyr::mutate(
operator = dplyr::if_else(operator == "Y", "Baltimore City Department of Recreation and Parks", "Other"),
acres = units::set_units(sf::st_area(geometry), "acres")
) %>%
dplyr::relocate(
geometry,
.after = tidyselect::everything()
) %>%
mutate(
name = stringr::str_trim(stringr::str_squish(name)),
name_alt = case_when(
(name == "Belnor Squares Park") ~ "Belnord Squares Park",
(name == "Courthouse Plaza") ~ "Cathy Hughes Plaza",
(name == "Ravens' Walk") ~ "RavensWalk", # 2023-12-08 https://www.baltimoreravens.com/game-day/ravenswalk/
(name == "Cottage Ave. Park") ~ name, # 2023-09-21 Planning Commission
(name == "Mt Vernon Square Park") ~ name,
(name == "Calvert & Madison Park") ~ name,
(name == "Lehigh & Gough Park") ~ name,
(name == "Ellwood Ave Park") ~ name,
(name == "Contee-Parago Traffic Island") ~ name,
(name == "Ambrose Kennedy Park") ~ name,
(name == "Madison Square Park") ~ name,
(name == "32nd Street Park") ~ name,
(name == "Harwood Avenue Park") ~ name,
(name == "Riverside Park Extension") ~ name,
.default = name_alt
),
name = case_when(
name == "Florence Cummings Park" ~ "Florence Cummins Park", # 2023-12-08 correction
name == "Pauline Faunteroy" ~ "Pauline Faunteroy Park",
name == "Mary E. Rodman Recreation Center" ~ "Mary E. Rodman Rec Center",
name_alt == "Cottage Ave. Park" ~ "Candy Stripe Park", # 2023-09-21
name_alt == "Mt Vernon Square Park" ~ "Mount Vernon Place",
name_alt == "Calvert & Madison Park" ~ "Mount Vernon Children's Park",
name_alt == "Lehigh & Gough Park" ~ "Gloria Hertzfelt Playground",
name_alt == "Belnor Squares Park" ~ "Library Square",
name_alt == "Ellwood Ave Park" ~ "Ellwood Park",
name_alt == "Contee-Parago Traffic Island" ~ "Contee-Parago Park",
name_alt == "Ambrose Kennedy Park" ~ "Henrietta Lacks Educational Park",
name_alt == "Madison Square Park" ~ "Nathan C. Irby, Jr. Park",
name_alt == "32nd Street Park" ~ "Abell Open Space",
name_alt == "Harwood Avenue Park" ~ "Harwood Park",
name_alt == "Riverside Park Extension" ~ "Riverside Park Extension", # 2023-10-02
.default = name
),
name_alt = case_when(
name == "Riverside Park Extension" ~ "Riverside Park", # 2023-10-02
TRUE ~ name_alt
),
name = case_when(
stringr::str_detect(name, "[:space:]St[:space:]P") ~ stringr::str_replace(name, " St P", " St. P"),
stringr::str_detect(name, "[:space:]Ave[:space:]P") ~ stringr::str_replace(name, " Ave P", " Ave. P"),
stringr::str_detect(name, "[:space:]Street[:space:]P") ~ stringr::str_replace(name, " Street P", " St. P"),
stringr::str_detect(name, "[:space:]Light[:space:]St$") ~ stringr::str_replace(name, " St", " St."),
stringr::str_detect(name, "[:space:]Avenue[:space:]P") ~ stringr::str_replace(name, " Avenue P", " Ave. P"),
.default = name
)
) |>
dplyr::mutate(
id = case_match(
name,
"Duncan Street Miracle Garden" ~ 322,
"Darley Park" ~ 336,
"Masonville Cove Environmental Center" ~ 334,
"Brentwood Commons" ~ 321,
"Northwood Baseball League" ~ 318,
.default = id
)
)
# FIXME: These parks are included in a DGS Asset list
# They may be OR zoning with a responsible agency
# https://publicworks.baltimorecity.gov/sites/default/files/Baltimore%20SWMP%20Update_FINAL%20DRAFT_3-28-23_Appendices.pdf
additional_parks <- tibble::tribble(
~name, ~id, ~street_address,
"Mosher St. Park", 307L, "1427 Eutaw Pl.",
"Charles Plaza", 310L, "100 N. Charles St.",
"Frederick & Brunswick Traffic Island", 309L, "Frederick Ave. and Brunswick St.",
"Cotwood Pl. Traffic Island", 308L, "3401 Cotwood Pl.",
"Sarah Ann Park", 304L, "1122 W. Saratoga St.",
"Rosedale & Belmont Park", 306L, "1403 Rosedale St.",
"St. Mary & Paca Traffic Island", 305L, "450 Saint Mary St.",
"Broadway Pier", 312L, "920 S. Broadway",
"Broadway Market Square", 311L, "1641 Lancaster St."
)
osm_parks <- getdata::get_osm_data(
location = mapbaltimore::baltimore_city,
key = "leisure",
value = "park",
osmdata = TRUE
)
osm_parks_rev <- bind_rows(
osm_parks$osm_polygons %>%
mutate(
osm_id = paste0("way/", osm_id)
) %>%
sf::st_cast("MULTIPOLYGON"),
osm_parks$osm_multipolygons %>%
mutate(
osm_id = paste0("relation/", osm_id)
)
) |>
dplyr::select(
osm_id, name
) |>
dplyr::filter(!is.na(name)) #|>
# naniar::replace_with_na(list(wikidata = "", start_date = ""))
osm_parks_name_matched <- osm_parks_rev %>%
filter(name %in% parks$name) %>%
sf::st_drop_geometry()
osm_xwalk <- tibble::tribble(
~name, ~osm_id_add,
"Courthouse Plaza", "way/1020465427",
"Pope John Paul II Prayer Garden", "way/1090360725",
"Chick Webb Memorial Rec Center", "node/358249524",
"Upton Boxing Center", "node/9362251051",
"Moore's Run Park", "relation/12764727",
"Atlantic Ave. Park", "relation/13007392",
"Shake n' Bake", "relation/13587201",
"Evesham Ave. Park", "relation/5771325",
"Boston St. Pier Park", "relation/6649001",
"Preston Gardens Park", "relation/6814275",
"Chinquapin Run Park", "relation/9352296",
"Stoney Run Park", "relation/9353383",
"Winner Ave. Park", "way/1007202043",
"Bocek Park", "way/100893180",
"President & Pratt St. Park", "way/1014903193",
"Newington Ave. Park", "way/1020465420",
"Carlton St. Park", "way/1020465421",
"Schroeder & Lombard Park", "way/1020465424",
"Fox St. Park", "way/1020465428",
"Miles Ave. Park", "way/1020465430",
"Montpelier & 30th St. Park", "way/1020465431",
"Woodbourne Ave. Park", "way/1020465740",
"Riverside Park", "way/103285201",
"Lehigh & Gough Park", "way/1035465876",
"Waverly Mini Park", "way/1081962109",
"Holocaust Memorial Park", "way/109485081",
"Cottage Ave. Park", "way/114693976",
"Greenspring Ave. Park", "way/114693991",
"Pall Mall & Shirley", "way/114693996",
"Shirley Ave. Park", "way/114694001",
"Thames St. Park", "way/115211504",
"Conway St. Park", "way/126145341",
"Stricker & Ramsey Park", "way/127010721",
"Elmley Ave. Park", "way/138384283",
"Vincent St. Park", "way/165342610",
"World Trade Plaza", "way/185099840",
"Baltimore Immigration Memorial Park", "way/208444707",
"Under Armour Waterfront Park", "way/208444711",
"Abell Open Space", "way/220687246",
"Arnold Sumpter Park", "way/220687249",
"Robert C. Marshall Park", "way/227894291",
"Buena Vista Park", "way/239263166",
"Pierce's Park", "way/242782258",
"Columbus Park", "way/242968653",
"Pauline Faunteroy Park", "way/255481074",
"Contee-Parago Park", "way/262584183",
"Saint Mary's Park", "way/262587660",
"Irvington Park", "way/262944613",
"Lakeland Park", "way/283033503",
"Paca St. Park", "way/283538339",
"Castle St. Park", "way/292628813",
"Janney St. Park", "way/292983554",
"Keyes Park", "way/32426907",
"Cecil Kirk Rec Center", "way/336339409",
"Greenmount Rec Center", "way/336352554",
"Forrest St. Park", "way/339540454",
"Saint Leo's Bocce Park", "way/360962326",
"Mount Royal Terrace Park", "way/379855071",
"Rozena Ridgley Park", "way/380019341",
"B & O Museum Park", "way/380020456",
"Battle Monument", "way/431237141",
"Cimaglia Park", "way/436726566",
"Robert & Mcculloh Park", "way/452160218",
"Lafayette Square Park", "way/49320694",
"Harlem Square Park", "way/49320695",
"Betty Hyatt Park", "way/495768187",
"Maisel St. Park", "way/524637577",
"Center Plaza", "way/530866324",
"Henry St. Park", "way/544546985",
"Henry H. Garnet Park", "way/628291631",
"Elm Park", "way/638323195",
"Hoes Heights Park", "way/638334715",
"Catherine St. Park", "way/683467763",
"McKeldin Plaza", "way/68624603",
"Johnston Square Park", "way/69489464",
"Kimberleligh Road Park", "way/699104068",
"Warwick Ave. Park", "way/703993923",
"Collington Sq Park", "way/71698840",
"Luzerne Ave. Park", "way/740552334",
"Willow Ave. Park", "way/765852714",
"Nathan C. Irby, Jr. Park", "way/80318086",
"Rosemont Park", "way/803377606",
"Belvedere & Sunset St. Park", "way/813758923",
"Saint Casmir's Park", "way/82422915",
"Penn & Melvin St. Park", "way/838874053",
"Russell St. Park", "way/838874054",
"Warner St. Park", "way/838874055",
"Union Square Park", "way/85585339",
"Franklin Square Park", "way/85585348",
"Joseph E. Lee Park", "way/85609472",
"Indiana Ave. Park", "way/935844574",
"Irvin Luckman Park", "way/95035178",
"1640 Light St.", "way/964597342"
)
parks_final <- parks %>%
left_join(osm_parks_name_matched, by = "name") %>%
left_join(osm_xwalk, by = "name") %>%
mutate(
osm_id = if_else(is.na(osm_id), osm_id_add, osm_id)
) %>%
select(-osm_id_add) %>%
distinct(name, id, address, .keep_all = TRUE)
# parks_final |>
# sfext::write_sf_ext("2023-10-02_parks.csv")
#
# mapbaltimore::parks |>
# sfext::write_sf_ext("mapbaltimore_parks.csv")
#
# dplyr::left_join(
# sf::st_drop_geometry(parks_final) |>
# dplyr::mutate(
# name_new = TRUE
# ),# |>
# mapbaltimore::parks |>
# dplyr::mutate(
# name_old = TRUE
# ), #|> filter(!is.na(id))
# #filter(!is.na(id)),
# by = "name"
# ) |>
# dplyr::relocate(
# starts_with("name"),
# .before = everything()
# )# |>
# # View()
parks <- parks_final |>
rename(
management = operator_name
)# |>
# parks <- map
usethis::use_data(parks, overwrite = TRUE)
# Water ----
baltimore_water_path <- "https://dotgis.baltimorecity.gov/arcgis/rest/services/DOT_Map_Services/DOT_Basemap/MapServer/7"
baltimore_water_source <- esri2sf::esri2sf(baltimore_water_path)
baltimore_water <- baltimore_water_source %>%
janitor::clean_names("snake") %>%
sf::st_transform(2804) |>
sf::st_join(
mapmaryland::md_water |>
sf::st_transform(2804) |>
dplyr::select(fullname),
largest = TRUE
) |>
naniar::replace_with_na(list(name = " ")) |>
dplyr::mutate(
name = dplyr::coalesce(name, fullname),
name = dplyr::case_match(
name,
"Jones Fls" ~ "Jones Falls",
"Gwynns Fls" ~ "Gwynns Falls",
"Northwest Hbr" ~ "Northwest Harbor",
"Patapsco Riv" ~ "Patapsco River",
"Colgate Crk" ~ "Colgate Creek",
"Curtis Crk" ~ "Curtis Creek",
"Harbor" ~ "Baltimore Harbor",
.default = name
),
acres = units::set_units(sf::st_area(.data[["geoms"]]), "acres"),
water = water == "Y"
) |>
dplyr::select(
name,
type,
subtype,
symbol,
water,
acres,
geometry = geoms
)
usethis::use_data(baltimore_water, overwrite = TRUE)
## Baltimore MIHP ----
# Import from iMap
# https://data.imap.maryland.gov/datasets/maryland-inventory-historic-properties-maryland-inventory-of-historic-properties/data
baltimore_mihp <-
getdata::get_esri_data(
"https://geodata.md.gov/imap/rest/services/Historic/MD_InventoryHistoricProperties/FeatureServer/0",
name = "Baltimore City",
name_col = "COUNTY",
crs = 2804
)
baltimore_mihp <-
dplyr::bind_rows(
baltimore_mihp,
getdata::get_esri_data(
"https://geodata.md.gov/imap/rest/services/Historic/MD_InventoryHistoricProperties/FeatureServer/0",
name = "BaltCity,BaltCo",
name_col = "COUNTY",
crs = 2804
)
)
# Rename columns
baltimore_mihp <- dplyr::rename(baltimore_mihp,
mihp_id = mihpid,
property_id = propertyid,
mihp_num = mihpno,
name = nam,
alternate_name = a,
full_address = fulladdr
)
baltimore_mihp <- baltimore_mihp |>
mutate(
name = stringr::str_trim(stringr::str_squish(name)),
alternate_name = stringr::str_trim(stringr::str_squish(alternate_name)),
full_address = stringr::str_trim(stringr::str_squish(full_address)),
name = if_else(name == " ", "", name),
alternate_name = if_else(alternate_name == " ", "", alternate_name),
full_address = if_else(full_address == " ", "", full_address),
sort_num = readr::parse_double(
stringr::str_replace(
stringr::str_remove_all(mihp_num, "^B-|^BA-|[:alpha:]"),
"-",
"."
)
),
) |>
naniar::replace_with_na(
list(name = "", alternate_name = "", full_address = "full_address")
)
# Remove unnecessary columns
baltimore_mihp <- baltimore_mihp |>
sfext::rename_sf_col() |>
dplyr::arrange(sort_num) |>
dplyr::select(-c(objectid, class, sort_num))
usethis::use_data(baltimore_mihp, overwrite = TRUE)
## Import U.S. Census 2019 boundary data using tigris
# Download blocks ----
baltimore_blocks <- tigris::blocks(state = state_fips, county = county_fips) %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake") %>%
dplyr::select(c(tractce20:name20, aland20:pop20))
usethis::use_data(baltimore_blocks, overwrite = TRUE)
# Download block groups ----
baltimore_block_groups <- tigris::block_groups(state = state_fips, county = county_fips) %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake") %>%
dplyr::select(-c(statefp, countyfp, mtfcc, funcstat))
usethis::use_data(baltimore_block_groups, overwrite = TRUE)
# Download tracts ----
baltimore_tracts <- tigris::tracts(state = state_fips, county = county_fips) %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake") %>%
dplyr::select(-c(statefp, countyfp, mtfcc, funcstat))
usethis::use_data(baltimore_tracts, overwrite = TRUE)
# Download PUMAs ----
md_pumas <- tigris::pumas(state = state_fips) %>%
sf::st_transform(selected_crs)
baltimore_pumas <- md_pumas %>%
dplyr::filter(PUMACE10 %in% c("00801", "00802", "00803", "00804", "00805")) %>%
janitor::clean_names("snake")
usethis::use_data(baltimore_pumas, overwrite = TRUE)
# Crosswalk: Neighborhoods to Tracts weighted by 2010 household population ----
# Make a weighted dataframe of neighborhoods and tracts for use with the cwi package
# Based on https://github.com/CT-Data-Haven/cwi/blob/master/data-raw/make_neighborhood_shares.R
options(tigris_use_cache = TRUE)
xwalk_blocks <- baltimore_blocks %>%
sf::st_drop_geometry() %>%
dplyr::left_join(sf::st_drop_geometry(baltimore_tracts), by = c("tractce20" = "tractce")) %>%
dplyr::select(block = geoid20, tract = geoid, block_name = name20, tract_name = namelsad)
# vars <-
# tidycensus::load_variables(year = 2020, dataset = "pl")
blocks_households <-
tidycensus::get_decennial(
geography = "block",
variables = "H1_002N",
# variables = "H013001", # Total households
state = "24",
county = "510",
year = 2020,
sumfile = "pl",
# sumfile = "sf1",
cache = TRUE,
geometry = TRUE
) %>%
janitor::clean_names()
xwalk_block2tract <-
blocks_households %>%
dplyr::left_join(xwalk_blocks, by = c("geoid" = "block")) %>%
dplyr::select(geoid, occupied_units_2020 = value)
# blocks_occupied_units <- tidycensus::get_decennial(
# geography = "block",
# variables = "H1_002N", # Total households
# state = "24",
# county = "510",
# year = 2020,
# sumfile = "sf1",
# cache = TRUE,
# geometry = FALSE
# ) %>%
# janitor::clean_names() %>%
# dplyr::select(geoid, occupied_units_2020 = value)
xwalk_block2tract <- blocks_households %>%
dplyr::left_join(xwalk_blocks, by = c("geoid" = "block")) %>%
dplyr::left_join(blocks_occupied_units, by = "geoid") %>%
dplyr::select(block = geoid, tract, households_2010 = value, occupied_units_2020, -name)
xwalk_neighborhood2tract <-
xwalk_block2tract %>%
dplyr::select(geoid, tract, occupied_units_2020) %>%
sf::st_transform(2804) %>%
sf::st_join(neighborhoods, left = FALSE, largest = TRUE) %>%
dplyr::filter(occupied_units_2020 > 0) %>%
sf::st_set_geometry(NULL) %>%
dplyr::group_by(tract, name) %>%
dplyr::summarise(
# households_2010 = sum(households_2010, na.rm = TRUE),
occupied_units_2020 = sum(occupied_units_2020, na.rm = TRUE)
) %>%
dplyr::mutate(
# weight_households = round(households_2010 / sum(households_2010, na.rm = TRUE), digits = 2),
weight_units = round(occupied_units_2020 / sum(occupied_units_2020, na.rm = TRUE), digits = 2)
) %>%
dplyr::ungroup() %>%
dplyr::rename(geoid = tract) %>%
dplyr::mutate(tract = stringr::str_sub(geoid, -6)) %>%
dplyr::select(name, geoid, tract, weight_units)
usethis::use_data(xwalk_neighborhood2tract, overwrite = TRUE)
inspire_plans_for_xwalk <-
inspire_plans %>%
bind_rows(
st_erase(baltimore_city, inspire_plans) %>% select(plan_name = name)
)
xwalk_inspire2tract <-
xwalk_block2tract %>%
dplyr::select(geoid, tract, occupied_units_2020) %>%
sf::st_transform(2804) %>%
sf::st_join(inspire_plans_for_xwalk, left = FALSE, largest = TRUE) %>%
dplyr::filter(occupied_units_2020 > 0) %>%
sf::st_set_geometry(NULL) %>%
dplyr::group_by(tract, plan_name) %>%
dplyr::summarise(
# households_2010 = sum(households_2010, na.rm = TRUE),
occupied_units_2020 = sum(occupied_units_2020, na.rm = TRUE)
) %>%
dplyr::mutate(
# weight_households = round(households_2010 / sum(households_2010, na.rm = TRUE), digits = 2),
weight_units = round(occupied_units_2020 / sum(occupied_units_2020, na.rm = TRUE), digits = 2)
) %>%
dplyr::ungroup() %>%
dplyr::rename(geoid = tract) %>%
dplyr::mutate(tract = stringr::str_sub(geoid, -6)) %>%
dplyr::select(plan_name, geoid, tract, weight_units)
xwalk_inspire2tract <-
xwalk_inspire2tract %>%
filter(plan_name != "Baltimore city")
usethis::use_data(xwalk_inspire2tract, overwrite = TRUE)
xwalk_block2tract %>%
sf::st_set_geometry(NULL) %>%
usethis::use_data(overwrite = TRUE)
# Set projected CRS (NAD83(HARN) / Maryland, meters)
selected_crs <- 2804
# NDC Projects ----
ndc_projects_path <- "https://services5.arcgis.com/o5xMIospaZLivipF/ArcGIS/rest/services/NDC_Projects_1968to2016/FeatureServer/0"
ndc_projects <- esri2sf::esri2sf(ndc_projects_path) %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake")
ndc_projects <- ndc_projects %>%
dplyr::select(
ndc_office = office,
ndc_program = program,
project_id = ndc_id,
project_name = proj_name,
project_type = proj_type,
project_status = proj_status,
start_date = date_open,
end_date = date_end,
client_name = client_org,
address = address,
city = town,
state = state,
zip_code,
geometry = geoms
) %>%
naniar::replace_with_na(replace = list(start_date = "N/A")) %>%
naniar::replace_with_na(replace = list(end_date = "N/A")) %>%
naniar::replace_with_na(replace = list(zip_code = "0")) %>%
dplyr::mutate(
start_year = stringr::str_sub(start_date, start = -4),
end_year = stringr::str_sub(end_date, start = -4)
)
# TODO: The NDC project data is not included in the package documentation yet
usethis::use_data(ndc_projects, overwrite = TRUE)
# Explore Baltimore Heritage stories ----
explore_baltimore <- jsonlite::fromJSON("https://explore.baltimoreheritage.org/items/browse?output=mobile-json")
explore_baltimore <- explore_baltimore$items %>%
dplyr::mutate(
url = paste0("https://explore.baltimoreheritage.org/items/show/", id)
)
explore_baltimore <- sfext::df_to_sf(explore_baltimore,
coords = c("longitude", "latitude"),
remove_coords = TRUE
)
explore_baltimore <- sf::st_transform(explore_baltimore, 2804)
usethis::use_data(explore_baltimore, overwrite = TRUE)
works <- sfext::read_sf_rdata("https://github.com/publicartbaltimore/inventory/raw/master/data/works.rda")
update_date <- "2023-01-18"
path <- glue(
"https://github.com/publicartbaltimore/inventory/raw/master/files/data/{update_date}_works-public.csv"
)
works <-
getdata::get_location_data(
data = path,
from_crs = 4326,
clean_names = TRUE
)
works <-
works %>%
dplyr::select(
id,
osm_id,
title = work_title,
location = location_name,
type,
medium,
status = current_status,
year,
year_accuracy,
creation_dedication_date,
primary_artist,
primary_artist_gender,
street_address,
city,
state,
zipcode,
dimensions,
program,
funding = funding_source,
artist_assistants,
architect,
fabricator,
location_desc = location_description,
indoor_outdoor_access = indoor_outdoor_accessible,
subject_person,
related_property,
property_ownership,
agency_or_insitution,
wikipedia_url
)
works <-
works %>%
mutate(
work_type = stringr::str_extract(type, ".+(?=,)|(?<!,).+$"),
work_type = forcats::fct_infreq(work_type),
work_type = forcats::fct_lump_n(work_type, 6),
work_type = forcats::fct_explicit_na(work_type)
)
works <- works %>%
sf::st_transform(2804) %>%
sf::st_join(
dplyr::select(mapbaltimore::csas, csa = name)
) %>%
sf::st_join(
dplyr::select(mapbaltimore::legislative_districts, legislative_district = name)
) %>%
sf::st_join(
dplyr::select(mapbaltimore::neighborhoods, neighborhood = name)
) %>%
sf::st_join(
dplyr::select(mapbaltimore::council_districts, council_district = name)
) %>%
dplyr::relocate(
neighborhood, csa, council_district, legislative_district,
.before = location_desc
) %>%
sf::st_transform(2804)
public_art <- works
public_art$work_type <- NULL
usethis::use_data(public_art, overwrite = TRUE)
selected_crs <- 2804
## Housing Market Typology ----
hmt_2017_path <- "https://geodata.baltimorecity.gov/egis/rest/services/Planning/Boundaries_and_Plans/MapServer/25"
hmt_2017 <- esri2sf::esri2sf(hmt_2017_path) %>%
janitor::clean_names("snake") %>%
sf::st_transform(selected_crs) # Transform to projected CRS
# https://planning.baltimorecity.gov/sites/default/files/FINAL_HMT2017_DataSeries_0518.pdf
hmt_2017 <- hmt_2017 %>%
dplyr::select(
geoid = bg, # all variables are derived from 2015 to 2017 data ()
geoid_part = geo_i_dw_splt,
cluster = mva17hrd_cd,
median_sales_price = msp1517eo,
sales_price_variation = vsp1517rsf, # Baltimore City real estate transactions 2015q3-2017q2
num_sales = csp1517rsf, #
num_foreclosure_filings = nfcl1517, # Baltimore City Circuit Court 2015q3-2017q2 foreclosure filings
perc_foreclosure_sales = pct_fcl_sale, # Baltimore City Circuit Court 2015q3-2017q2 foreclosure filings
perc_homeowners = phhooac6bg, # July 2017 data
perc_permits_over10k = pct10k_prmt, # Baltimore Housing 2015q3-2017q2 Database
vacant_lots_bldgs_per_acre_res = p_vl_vb_r_acr, # Baltimore Housing July 2017 Database
units_per_acre_res = h_up_res_acre, # Baltimore Housing July 2017 Database
geometry = geoms
) %>%
dplyr::mutate(
part = dplyr::case_when(
stringr::str_detect(geoid_part, "[:alpha:]") ~ stringr::str_extract(geoid_part, "[:alpha:]")
),
cluster = dplyr::case_when(
cluster == "NonResidential" ~ "Non-Residential",
cluster == "Mixed Market/Subsd Rental" ~ "Mixed Market/Subsidized Rental Market",
TRUE ~ cluster
),
perc_homeowners = dplyr::if_else(perc_homeowners != -9999, perc_homeowners / 100, 0),
perc_foreclosure_sales = round(perc_foreclosure_sales, digits = 4),
perc_permits_over10k = round(perc_permits_over10k, digits = 4),
vacant_lots_bldgs_per_acre_res = round(vacant_lots_bldgs_per_acre_res, digits = 4)
)
cluster_groups <- tibble::tribble(
~cluster, ~cluster_group,
"A", "A",
"B", "B & C",
"C", "B & C",
"D", "D & E",
"E", "D & E",
"F", "F, G, & H",
"G", "F, G, & H",
"H", "F, G, & H",
"I", "I & J",
"J", "I & J",
"Rental Market 1", "RM 1 & RM 2",
"Rental Market 2", "RM 1 & RM 2",
"Subsidized Rental Market", "Other Residential",
"Mixed Market/Subsidized Rental Market", "Other Residential",
"Non-Residential", "Non-Residential"
)
hmt_2017 <- hmt_2017 %>%
dplyr::left_join(cluster_groups, by = "cluster") %>%
dplyr::relocate(cluster_group, .after = cluster) %>%
dplyr::relocate(part, .after = geoid)
hmt_2017$cluster <- forcats::fct_relevel(hmt_2017$cluster, cluster_groups$cluster)
hmt_2017$cluster_group <- forcats::fct_relevel(hmt_2017$cluster_group, unique(cluster_groups$cluster_group))
usethis::use_data(hmt_2017, overwrite = TRUE)
# Based on a combination of this data, scraped website data and bcpss::nces_school_directory_SY19
# "https://services1.arcgis.com/mVFRs7NF4iFitgbY/arcgis/rest/services/21st_Century_Schools/FeatureServer/0"
schools_21stc_sheet_url <-
"https://docs.google.com/spreadsheets/d/1Ve9J8T-Q5A61MgEhtxmMYCrjnVrkwR0ynsf4DAJc26Y/edit?usp=sharing"
schools_21stc_sheet_url <- "/Users/elipousson/Downloads/Comparison – 21st Century Schools + INSPIRE - schools_21stc.csv"
schools_21stc_sheet <-
read_sf_ext(path = schools_21stc_sheet_url, from_crs = 3857) %>%
select(-c(address, zip)) %>%
st_transform_ext(crs = 2804)
library(readr)
school_info <-
read_csv("/Users/elipousson/Downloads/Schoollist.csv",
col_types = cols(
`School Number` = col_double(),
`School Name` = col_character(),
Address = col_character(),
`Address Line 2` = col_logical(),
Zip = col_double(),
Phone = col_character(),
`School leader` = col_character(),
Website = col_character(),
`Zone Number` = col_character(),
Description = col_character(),
`Community learning network number` = col_double(),
`Official state grade band` = col_character(),
`Grades served` = col_character(),
`Management type` = col_character(),
`Enrollment type` = col_character(),
`Elementary Opening Bell` = col_character(),
`Elementary Closing Bell` = col_character(),
`Middle Opening bell` = col_character(),
`Middle Closing bell` = col_character(),
`High Opening Bell` = col_character(),
`High Closing Bell` = col_character(),
`Academics: Approach` = col_character(),
`Academics: Special Programming` = col_character(),
`Academics: CTE` = col_character(),
`Academics: AP` = col_character(),
`Title I` = col_character(),
Extracurriculars = col_character(),
Services = col_character(),
`Building info` = col_character(),
`Address Latitude` = col_double(),
`Address Longitude` = col_character(),
MSDE = col_character(),
`School Effectiveness` = col_logical(),
`School Performance` = col_character(),
`School Profile` = col_character(),
`Renewal Report` = col_character(),
`Survey Results` = col_character(),
`5 Star Rating` = col_logical(),
`SAT Average` = col_double(),
`Student Uniform` = col_character(),
`Organized Parent Group` = col_character(),
`Video Image` = col_character(),
`Video URL` = col_logical(),
`Community Partnerships` = col_character()
)
) %>%
janitor::clean_names("snake") %>%
rename_with_xwalk(
list(
"school_website_url" = "website",
"school_directory_name" = "school_name",
"school_address_lat" = "address_latitude",
"school_address_lon" = "address_longitude",
"bldg_info" = "building_info",
"description_yn" = "description",
"parent_org_yn" = "organized_parent_group",
"msde_url" = "msde",
"school_performance_url" = "school_performance",
"school_profile_url" = "school_profile",
"renewal_report_url" = "renewal_report",
"survey_results_url" = "survey_results"
)
) %>%
mutate(
opening_bell = coalesce(elementary_opening_bell, middle_opening_bell, high_opening_bell),
closing_bell = coalesce(elementary_closing_bell, middle_closing_bell, high_closing_bell),
description_yn = if_else(description_yn == "yes", "Y", "N"),
parent_org_yn = if_else(parent_org_yn == "No", "N", "Y")
) %>%
select(-c(
address_line_2, elementary_opening_bell, middle_opening_bell, high_opening_bell,
elementary_closing_bell, middle_closing_bell, high_closing_bell,
school_effectiveness, x5_star_rating, video_image, video_url # ,
# NOTE: Dropping official state grade band because the data in the reference sheet is accurate
# official_state_grade_band
)) %>%
relocate(ends_with("_yn"), .after = everything()) %>%
relocate(ends_with("_url"), .after = everything())
schools_21stc <-
schools_21stc_sheet %>%
left_join(school_info, by = "school_number") %>%
bind_boundary_col(
boundary = list(
"neighborhood" = mapbaltimore::neighborhoods,
"council_district" = mapbaltimore::council_districts,
"planning_district" = mapbaltimore::planning_districts %>% rename(label = name, name = id)
)
) %>%
relocate(
ends_with("lon"),
.after = everything()
) %>%
relocate(
ends_with("lat"),
.after = everything()
) %>%
relocate_sf_col()
usethis::use_data(schools_21stc, overwrite = TRUE)
url <- "https://airtable.com/appZPNXZR398hkvm9/tbldyiXaNuIzyR7bu/viw4vYvWYzQWWeJAL"
# NOTE: This requires the forked development version of rairtable
# Install with the following
# pak::pkg_install("elipousson/rairtable@dev")
library(rairtable)
buildings_21stc <- rairtable::read_airtable_records(url = url, cell_format = "string")
buildings_21stc <- buildings_21stc |>
mutate(
`Combined school` = if_else(is.na(`Combined school`), "N", "Y")
)
buildings_21stc <- buildings_21stc |>
arrange(bldg_name, `Combined school`) |>
filter(!is.na(`INSPIRE Plan`)) |>
group_by(bldg_name) |>
reframe(
name = bldg_name,
bldg_name = paste0(unique(bldg_name), collapse = ", "),
bldg_name_short = paste0(unique(bldg_name_short), collapse = ", "),
project_type = paste0(unique(balt21stc_type), collapse = ", "),
project_url = paste0(unique(balt21stc_url), collapse = ", "),
building_occupied = unique(occupied_report),
inspire_plan = paste0(unique(`INSPIRE Plan`), collapse = ", "),
inspire_plan_url = paste0(unique(`INSPIRE Plan URL`), collapse = ", "),
school_names = paste0(unique(school_name), collapse = " and "),
school_names_short = paste0(unique(school_name_short), collapse = " and "),
school_numbers = paste0(unique(school_number), collapse = ", "),
grade_bands = paste0(unique(grade_band), collapse = ", "),
grades_served = paste0(unique(grades_served), collapse = ", "),
address = unique(address),
city = unique(city),
state = unique(state),
zip = unique(zip),
lon = unique(lon)[[1]],
lat = unique(lat)[[1]]
) |>
filter(!is.na(lon)) |>
distinct(bldg_name, .keep_all = TRUE) |>
sfext::df_to_sf(coords = c("lon", "lat")) |>
sf::st_transform(2804)
usethis::use_data(buildings_21stc, overwrite = TRUE)
adopted_plans_path <-
# FIXME: The original link for this data no longer works but the new data is missing key information
# "https://geodata.baltimorecity.gov/egis/rest/services/Planning/Boundaries_and_Plans/MapServer/72"
# "https://geodata.baltimorecity.gov/egis/rest/services/Planning/Boundaries/MapServer/39"
"https://geodata.baltimorecity.gov/egis/rest/services/Housing/dmxCityPrograms/MapServer/8"
inspire_path <-
"https://geodata.baltimorecity.gov/egis/rest/services/Planning/Boundaries/MapServer/19"
inspire <-
sfext::read_sf_ext(url = inspire_path)
adopted_plans <-
sfext::read_sf_ext(url = adopted_plans_path) |>
sf::st_transform(crs = selected_crs)
adopted_plans <- adopted_plans %>%
sfext::rename_sf_col() %>%
dplyr::select(
plan_name = AREA_NAME,
year_adopted = STATUS,
url = URL
) %>%
# dplyr::left_join(
# mapbaltimore::adopted_plans |>
# sf::st_drop_geometry()
# ) |>
dplyr::mutate(
year_adopted = stringr::str_sub(year_adopted, start = -4),
program = dplyr::case_when(
stringr::str_detect(plan_name, "(SNAP)") ~ "Strategic Neighborhood Action Plan (SNAP)",
stringr::str_detect(plan_name, "[:space:]TAP") ~ "Urban Land Institute Technical Assistance Panel (TAP)",
stringr::str_detect(plan_name, "[:space:]INSPIRE") ~ "INSPIRE (Investing in Neighborhoods and Schools to Promote Improvement, Revitalization, and Excellence)"
)
) %>%
dplyr::relocate(geometry, .after = program) %>%
dplyr::relocate(program, .after = year_adopted)
lincs_corridors_path <- # "https://geodata.baltimorecity.gov/egis/rest/services/Planning/Boundaries_and_Plans/MapServer/37"
"https://geodata.baltimorecity.gov/egis/rest/services/Housing/dmxCityPrograms/MapServer/34"
lincs_corridors <- esri2sf::esri2sf(lincs_corridors_path, crs = selected_crs) %>%
janitor::clean_names("snake") %>%
sf::st_transform(selected_crs) %>%
dplyr::filter(objectid != 4)
lincs_corridors$plan_name <- c("Greenmount Avenue LINCS Plan", "Liberty Heights Avenue/Garrison Boulevard LINCS Plan", "East North Avenue LINCS Plan", "Pennsylvania Avenue/North Avenue LINCS Plan")
lincs_corridors$year_adopted <- c("2016", "2016", "2017", "2016")
lincs_corridors$program <- "LINCS (Leveraging Investments in Neighborhood Corridors)"
lincs_corridors$url <- c(
"https://planning.baltimorecity.gov/greenmount-lincs",
"http://planning.baltimorecity.gov/liberty-heights-lincs",
"https://planning.baltimorecity.gov/lincs-east-north-avenue",
"http://planning.baltimorecity.gov/penn-north-lincs"
)
lincs_corridors <- lincs_corridors %>%
dplyr::select(-c(objectid, shape_st_length), plan_name, year_adopted, program, url, geometry = geoms)
adopted_plans <- dplyr::bind_rows(adopted_plans, lincs_corridors) |>
dplyr::arrange(year_adopted)
usethis::use_data(adopted_plans, overwrite = TRUE)
## Zoning ----
# Set path to Baltimore City Department of Planning Zoning hosted ArcGIS MapServer layer
zoning_path <- "https://opendata.baltimorecity.gov/egis/rest/services/Hosted/Zoning/FeatureServer/0"
# Import zoning data with esri2sf package
zoning <- esri2sf::esri2sf(zoning_path)
# Clean column names
zoning <- janitor::clean_names(zoning, "snake")
# Transform to projected CRS
zoning <- sf::st_transform(zoning, 2804)
# Replace blank overlay values with NA
zoning$overlay[zoning$overlay %in% c(" ", "")] <- NA
# Select relevant columns
zoning <- dplyr::select(zoning,
zoning,
overlay,
label,
geometry = geoms
)
# Make valid to avoid "Ring Self-intersection" error when cropped
zoning <- sf::st_make_valid(zoning)
zoning_legend <- tibble::tribble(
~code, ~category, ~name,
"AU", "Special Purpose Districts", "Adult Use Overlay Zoning District",
"BSC", "Industrial Districts", "Bio-Science Campus Zoning District",
"C-1", "Commercial Districts", "Neighborhood Business Zoning District",
"C-1-E", "Commercial Districts", "Neighborhood Business and Entertainment Zoning District",
"C-1-VC", "Commercial Districts", "Neighborhood Business Zoning District (Village Center)",
"C-2", "Commercial Districts", "Community Commercial Zoning District",
"C-3", "Commercial Districts", "General Commercial Zoning District",
"C-4", "Commercial Districts", "Heavy Commercial Zoning District",
"C-5", "Commercial Districts", "Downtown District",
"CBCA", "Open-Space and Environmental Districts", "Chesapeake Bay Critical Area Overlay Zoning District",
"D-MU", "Special Purpose Districts", "Detached Dwelling Mixed-Use Overlay District",
"EC-1", "Special Purpose Districts", "Educational Campus Zoning District",
"EC-2", "Special Purpose Districts", "Educational Campus Zoning District",
"FP", "Open-Space and Environmental Districts", "Floodplain Overlay Zoning District",
"H", "Special Purpose Districts", "Hospital Campus Zoning District",
"I-1", "Industrial Districts", "Light Industrial Zoning District",
"I-2", "Industrial Districts", "General Industrial Zoning District",
"IMU-1", "Industrial Districts", "Industrial Mixed-Use Zoning District",
"IMU-2", "Industrial Districts", "Industrial Mixed-Use Zoning District",
"MI", "Industrial Districts", "Maritime Industrial Zoning District",
"OIC", "Industrial Districts", "Office-Industrial Campus Zoning District",
"OR-1", "Special Purpose Districts", "Office-Residential Zoning District",
"OR-2", "Special Purpose Districts", "Office-Residential Zoning District",
"OS", "Open-Space and Environmental Districts", "Open-Space Zoning District",
"PC", "Special Purpose Districts", "Port Covington Zoning District",
"R-1", "Detached and Semi-Detached Residential Districts", "Detached Residential Zoning District",
"R-1-A", "Detached and Semi-Detached Residential Districts", "Detached Residential Zoning District",
"R-1-B", "Detached and Semi-Detached Residential Districts", "Detached Residential Zoning District",
"R-1-C", "Detached and Semi-Detached Residential Districts", "Detached Residential Zoning District",
"R-1-D", "Detached and Semi-Detached Residential Districts", "Detached Residential Zoning District",
"R-1-E", "Detached and Semi-Detached Residential Districts", "Detached Residential Zoning District",
"R-2", "Detached and Semi-Detached Residential Districts", "Detached and Semi-Detached Residential Zoning District",
"R-3", "Detached and Semi-Detached Residential Districts", "Detached Residential Zoning District",
"R-4", "Detached and Semi-Detached Residential Districts", "Detached and Semi-Detached Residential Zoning District",
"R-5", "Rowhouse and Multi-Family Residential Districts", "Rowhouse and Multi-Family Residential Zoning District",
"R-6", "Rowhouse and Multi-Family Residential Districts", "Rowhouse and Multi-Family Residential Zoning District",
"R-7", "Rowhouse and Multi-Family Residential Districts", "Rowhouse and Multi-Family Residential Zoning District",
"R-8", "Rowhouse and Multi-Family Residential Districts", "Rowhouse and Multi-Family Residential Zoning District",
"R-9", "Rowhouse and Multi-Family Residential Districts", "Rowhouse and Multi-Family Residential Zoning District",
"R-10", "Detached and Semi-Detached Residential Districts", "Rowhouse and Multi-Family Residential Zoning District",
"R-MU", "Special Purpose Districts", "Rowhouse Mixed-Use Overlay District",
"T", "Special Purpose Districts", "Transportation Zoning District",
"TOD-1", "Special Purpose Districts", "Transit-Oriented Development District",
"TOD-2", "Special Purpose Districts", "Transit-Oriented Development District",
"TOD-3", "Special Purpose Districts", "Transit-Oriented Development District",
"TOD-4", "Special Purpose Districts", "Transit-Oriented Development District",
"W-1", "Special Purpose Districts", "Waterfront Overlay Zoning District",
"W-2", "Special Purpose Districts", "Waterfront Overlay Zoning District",
"PC-1", "Special Purpose Districts", "Port Covington Zoning District",
"PC-2", "Special Purpose Districts", "Port Covington Zoning District",
"PC-3", "Special Purpose Districts", "Port Covington Zoning District",
"PC-4", "Special Purpose Districts", "Port Covington Zoning District",
"C-5-TO", "Commercial Districts", "Downtown District",
"C-5-HS", "Commercial Districts", "Downtown District",
"C-5-DC", "Commercial Districts", "Downtown District",
"C-5-G", "Commercial Districts", "Downtown District",
"C-5-HT", "Commercial Districts", "Downtown District",
"C-5-IH", "Commercial Districts", "Downtown District",
"C-5-DE", "Commercial Districts", "Downtown District"
)
zoning <-
dplyr::left_join(
x = zoning,
y = zoning_legend %>% rename(zoning = code),
by = "zoning"
) # %>%
dplyr::left_join(zoning_legend, by = c("overlay" = "code"), suffix = c("_zoning", "_overlay"))
usethis::use_data(zoning, overwrite = TRUE)
## MTA Bus Lines ----
# Import Maryland Transit Administration bus line data (current as of July 12, 2020)
# https://data.imap.maryland.gov/datasets/maryland-transit-mta-bus-lines-1
mta_bus_lines <-
getdata::get_esri_data(
"https://geodata.md.gov/imap/rest/services/Transportation/MD_Transit/FeatureServer/10",
crs = selected_crs
) %>%
dplyr::select(-c(distribution_policy, objectid))
mta_bus_lines <- mta_bus_lines %>%
sfext::rename_sf_col() %>%
dplyr::mutate(
frequent = dplyr::case_when(
stringr::str_detect(route_number, "- Supplemental Service$") ~ FALSE,
stringr::str_detect(route_number, "^CityLink") ~ TRUE,
route_number %in% c("22", "26", "80", "54", "30", "85") ~ TRUE,
TRUE ~ FALSE
),
school = dplyr::case_when(
stringr::str_detect(route_number, "- Supplemental Service$") ~ TRUE,
TRUE ~ FALSE
),
route_abb = dplyr::case_when(
route_number == "CityLink BLUE" ~ "BL",
route_number == "CityLink BROWN" ~ "BR",
route_number == "CityLink GOLD" ~ "GD",
route_number == "CityLink GREEN" ~ "GR",
route_number == "CityLink LIME" ~ "LM",
route_number == "CityLink NAVY" ~ "NV",
route_number == "CityLink ORANGE" ~ "OR",
route_number == "CityLink PINK" ~ "PK",
route_number == "CityLink RED" ~ "RD",
route_number == "CityLink SILVER" ~ "SV",
route_number == "CityLink YELLOW" ~ "YW",
route_number == "CityLink PURPLE" ~ "PR",
route_number == "CityLink BLUE - Supplemental Service" ~ "BL SCH",
route_number == "CityLink BROWN - Supplemental Service" ~ "BR SCH",
route_number == "CityLink GOLD - Supplemental Service" ~ "GD SCH",
route_number == "CityLink GREEN - Supplemental Service" ~ "GR SCH",
route_number == "CityLink NAVY - Supplemental Service" ~ "NV SCH",
route_number == "CityLink ORANGE - Supplemental Service" ~ "OR SCH",
route_number == "CityLink PURPLE - Supplemental Service" ~ "PR SCH",
route_number == "CityLink RED - Supplemental Service" ~ "RD SCH",
route_number == "CityLink SILVER - Supplemental Service" ~ "SV SCH",
school ~ paste(stringr::str_remove(route_number, " - Supplemental Service$"), "SCH"),
TRUE ~ route_number
),
.before = geometry
) %>%
dplyr::relocate(route_abb, .after = route_number)
usethis::use_data(mta_bus_lines, overwrite = TRUE)
## MTA Bus Stops ----
mta_bus_stops <- getdata::get_esri_data("https://geodata.md.gov/imap/rest/services/Transportation/MD_Transit/FeatureServer/9",
crs = selected_crs
) %>%
sfext::rename_sf_col()
frequent_lines <- dplyr::filter(mta_bus_lines, frequent) %>%
dplyr::pull(route_abb)
mta_bus_stops <- mta_bus_stops %>%
dplyr::mutate(
stop_name = stringr::str_squish(stop_name),
shelter = dplyr::if_else(shelter == "Yes", TRUE, FALSE),
direction = dplyr::case_when(
stringr::str_detect(stop_name, "[:space:]nb") ~ "nb",
stringr::str_detect(stop_name, "[:space:]eb") ~ "eb",
stringr::str_detect(stop_name, "[:space:]sb") ~ "sb",
stringr::str_detect(stop_name, "[:space:]wb") ~ "wb"
), # mb? fs?,
stop_location = dplyr::case_when(
stringr::str_detect(stop_name, "[:space:]fs") ~ "far side", # far side?
stringr::str_detect(stop_name, "[:space:]mb") ~ "midblock", # mid block?
stringr::str_detect(stop_name, "[:space:]opp[:space:]") ~ "opposite",
stringr::str_detect(stop_name, "[:space:]mid[:space:]") ~ "midblock",
stringr::str_detect(stop_name, "[:space:]ns") ~ "near side" # near side?
),
routes_served = stringr::str_replace_all(
routes_served,
c(
"GREEN" = "GR",
"BLUE" = "BL",
"BROWN" = "BR",
"GOLD" = "GD",
"GREEN" = "GR",
"LIME" = "LM",
"NAVY" = "NV",
"ORANGE" = "OR",
"PINK" = "PK",
"RED" = "RD",
"SILVER" = "SV",
"YELLOW" = "YW",
"PURPLE" = "PR"
)
),
routes_served = stringr::str_remove_all(routes_served, "CityLink"),
routes_served_sep = stringr::str_remove_all(routes_served, "[:space:]"),
routes_served_sep = stringr::str_replace_all(routes_served_sep, ",", ";"),
routes_served_sep = stringr::str_split(routes_served_sep, pattern = ";")
)
mta_bus_stops$frequent <- vapply(
mta_bus_stops$routes_served_sep,
function(x) {
any(stringr::str_detect(x, paste0(frequent_lines, collapse = "|")))
},
TRUE
)
mta_bus_stops <- mta_bus_stops %>%
dplyr::as_tibble() %>%
sf::st_as_sf() %>%
dplyr::relocate(stop_id, .before = stop_name) %>%
dplyr::relocate(geometry, .after = tidyselect::everything()) %>%
dplyr::select(-c(distribution_policy, routes_served_sep)) %>%
dplyr::select(-objectid)
usethis::use_data(mta_bus_stops, overwrite = TRUE)
## MTA SubwayLink Lines ----
mta_subway_lines <- esri2sf::esri2sf("https://geodata.md.gov/imap/rest/services/Transportation/MD_Transit/FeatureServer/5")
mta_subway_lines <- janitor::clean_names(mta_subway_lines, "snake")
mta_subway_lines <- sf::st_transform(mta_subway_lines, 2804)
mta_subway_lines <- dplyr::select(mta_subway_lines,
id = objectid,
rail_name,
mode = trans_mode,
tunnel,
direction,
miles,
status = line_statu,
geometry = geoms
)
usethis::use_data(mta_subway_lines, overwrite = TRUE)
## Charm City Circulator Stopsand Routes ----
circulator_routes <- esri2sf::esri2sf("https://egisdata.baltimorecity.gov/egis/rest/services/CityView/Charm_City_Circulator/MapServer/1") %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake") %>%
dplyr::select(
route_name,
alt_route_name = alt_name,
geometry = geoms
)
usethis::use_data(circulator_routes, overwrite = TRUE)
circulator_stops <- esri2sf::esri2sf("https://egisdata.baltimorecity.gov/egis/rest/services/CityView/Charm_City_Circulator/MapServer/0") %>%
sf::st_transform(selected_crs) %>%
janitor::clean_names("snake") %>%
dplyr::mutate(
route = stringr::str_to_sentence(route)
) %>%
dplyr::select(
stop_num = stop,
stop_location = stop_locat,
corner,
route_name = route,
geometry = geoms
) %>%
naniar::replace_with_na(list(corner = c(" ", " ", "n/a")))
usethis::use_data(circulator_stops, overwrite = TRUE)
## MTA SubwayLink Stations ----
# https://data.imap.maryland.gov/datasets/maryland::maryland-transit-metro-subwaylink-stations/about
mta_subway_stations <- sf::read_sf("https://opendata.arcgis.com/datasets/76579336f7be446a9111eacf46c933b0_4.geojson")
mta_subway_stations <- janitor::clean_names(mta_subway_stations, "snake")
mta_subway_stations <- sf::st_transform(mta_subway_stations, 2804)
mta_subway_stations <- dplyr::select(mta_subway_stations,
id = objectid_1,
name,
address,
city,
state,
mode = transit_mo,
avg_wkdy,
avg_wknd,
facility_type,
geometry
)
usethis::use_data(mta_subway_stations, overwrite = TRUE)
# MTA Light Rail Line
mta_light_rail_lines <- sf::read_sf("https://opendata.arcgis.com/datasets/c7cb3ce4aaac4deb921e2a154cf22205_3.geojson") %>%
janitor::clean_names("snake") %>%
sf::st_transform(selected_crs) %>%
dplyr::select(
id = objectid_1,
rail_name,
mode = trans_mode,
tunnel,
direction,
miles,
status = line_statu,
geometry
)
usethis::use_data(mta_light_rail_lines, overwrite = TRUE)
# MTA Light Rail Stations
mta_light_rail_stations <- sf::read_sf("https://opendata.arcgis.com/datasets/c65b32c3c23f43169797f7b762ba1770_2.geojson") %>%
janitor::clean_names("snake") %>%
sf::st_transform(selected_crs) %>%
dplyr::select(
id = objectid_1,
name,
address,
city,
state,
zipcode = zip,
mode = transit_mo,
avg_wkdy,
avg_wknd,
facility_type,
geometry
)
usethis::use_data(mta_light_rail_stations, overwrite = TRUE)
## MTA MARC Train Lines
# "https://services.arcgis.com/njFNhDsUCentVYJW/arcgis/rest/services/DC_Metro_Bus_Train_Lines_Stations/FeatureServer/10"
mta_marc_lines <-
sf::read_sf("https://opendata.arcgis.com/datasets/de0efbe9f8884ac5aa69864b6b3ff633_10.geojson") %>%
janitor::clean_names("snake") %>%
sf::st_transform(selected_crs) %>%
dplyr::select(
id = objectid_1,
rail_name,
mode = trans_mode,
tunnel,
direction,
miles,
status = line_statu,
geometry
)
usethis::use_data(mta_marc_lines, overwrite = TRUE)
mta_marc_stations <-
sf::read_sf("https://opendata.arcgis.com/datasets/e476dcb6dc154683ab63f23472bed5d6_6.geojson") %>%
janitor::clean_names("snake") %>%
sf::st_transform(selected_crs) %>%
dplyr::select(
id = objectid_1,
name,
address,
city,
state,
zipcode = zip,
line_name,
mode = transit_mo,
avg_wkdy,
avg_wknd,
facility_type,
geometry
)
usethis::use_data(mta_marc_stations, overwrite = TRUE)
## Streets ----
streets_path <- "https://dotgis.baltimorecity.gov/arcgis/rest/services/DOT_Map_Services/DOT_Basemap/MapServer/4"
streets <- esri2sf::esri2sf(streets_path) %>%
janitor::clean_names("snake") %>%
sf::st_transform(2804)
sha_class_label_list <- tibble::tribble(
~sha_class, ~sha_class_label, ~functional_class,
"INT", "Interstate and Principal Arterial", 1,
"FWY", "Freeway and Expressway", 2,
"PART", "Other Principal Arterial Street", 3,
"MART", "Minor Arterial Street", 4,
"COLL", "Collector Street", 5,
"LOC", "Local Street", 7
)
functional_class_list <- tibble::tribble(
~sha_class, ~functional_class, ~functional_class_desc,
"INT", 1, "Interstate",
"FWY", 2, "Principal Arterial – Other Freeways and Expressways",
"PART", 3, "Principal Arterial – Other",
"MART", 4, "Minor Arterial",
"COLL", 5, "Major Collector",
"COLL", 6, "Minor Collector",
"LOC", 7, "Local"
)
subtype_label <- tibble::tribble(
~subtype, ~subtype_label,
"STRALY", "Alley",
"STRPRD", "Paved Road",
"STRR", "Ramp",
"STREX", "Limited Access",
"STRFIC", "Fictitious Centerline Segment",
"STRNDR", NA,
"STRURD", "Unpaved Road",
"STCLN", "County Street Centerline",
"STRTN", "Tunnel"
)
streets <- streets %>%
dplyr::select(-c(objectid_1:edit_date, flag:comments, shape_leng, place, zipcode:shape_st_length)) %>%
dplyr::left_join(sha_class_label_list, by = "sha_class") %>%
dplyr::relocate(sha_class_label, .after = sha_class) %>%
dplyr::mutate(
sha_class_label = forcats::fct_relevel(sha_class_label, sha_class_label_list$sha_class_label),
dplyr::across(
tidyselect::where(is.character),
~ .x %>%
stringr::str_trim() %>%
stringr::str_squish()
)
) %>%
naniar::replace_with_na(list(fullname = "", feanme = "")) %>%
dplyr::left_join(subtype_label, by = "subtype") %>%
dplyr::relocate(subtype_label, .after = subtype) %>%
dplyr::rename(geometry = geoms)
usethis::use_data(streets, overwrite = TRUE)
# Named intersections ----
intersections <- baltimore_city %>%
buffer_area(dist = 200) %>%
get_area_data(data = "edge_of_pavement") %>%
dplyr::filter(type == "RDINT") %>%
dplyr::select(-type)
area_around_intersections <- intersections %>%
buffer_area(dist = 20)
intersection_pts <- intersections %>%
sf::st_centroid()
intersection_streets <- streets %>%
dplyr::mutate(fullname = stringr::str_trim(stringr::str_squish(fullname))) %>%
dplyr::group_by(fullname) %>%
dplyr::summarise(geometry = sf::st_union(geometry)) %>%
sf::st_intersection(area_around_intersections)
named_intersections <- intersection_streets %>%
sf::st_drop_geometry() %>%
dplyr::group_by(id) %>%
dplyr::summarise(
name = stringr::str_replace(paste0(fullname, collapse = " & "), "^&|^[:space:]&[:space:]", "")
) %>%
naniar::replace_with_na(replace = list(name = ""))
named_intersections_sf <- intersection_pts %>%
dplyr::left_join(named_intersections) %>%
dplyr::rename(geometry = geom)
named_intersections <- named_intersections_sf
usethis::use_data(named_intersections, overwrite = TRUE)
request_types <- request_types %>%
mutate(
request_type = case_when(
request_type == "SW-Clean Up (Mayor�s Spring Cleanup)" ~ "SW-Clean Up (Mayor’s Spring Cleanup)",
request_type == "SW-Clean Up (Mayor�s Fall Cleanup)" ~ "SW-Clean Up (Mayor’s Fall Cleanup)",
TRUE ~ request_type
)
)
usethis::use_data(request_types, overwrite = TRUE)
baltimore_msa_water <- baltimore_msa_counties$countyfp %>%
purrr::map_dfr(
~ tigris::area_water(state = "MD", county = .x)
) %>%
sf::st_simplify(dTolerance = 1)
baltimore_msa_water <- baltimore_msa_water %>%
st_transform(2804) %>%
janitor::clean_names("snake")
usethis::use_data(baltimore_msa_water, overwrite = TRUE)
url <- "https://geodata.baltimorecity.gov/egis/rest/services/CityView/CHAS_Historic_DIST_ADDED/MapServer/0"
chap_districts_geodata <- getdata::get_esri_data(url, crs = 2804)
chap_district_info <- tibble::tribble(
~name, ~url, ~deed_covenant, ~overlaps_nr_district,
"Ashburton", "https://chap.baltimorecity.gov/ashburton", FALSE, FALSE,
"Auchentoroly Terrace", "http://chap.baltimorecity.gov/auchentorolyterrace", FALSE, TRUE,
"Bancroft Park", "http://chap.baltimorecity.gov/historic-districts/maps/bancroftpark", FALSE, FALSE,
"Barclay/Greenmount", "http://chap.baltimorecity.gov/historic-districts/maps/barclaygreenmount", FALSE, FALSE,
"Better Waverly", "http://chap.baltimorecity.gov/historic-districts/maps/betterwaverly", FALSE, FALSE,
"Bolton Hill", "http://chap.baltimorecity.gov/historic-districts/maps/boltonhill", FALSE, TRUE,
"Butcher's Hill", "http://chap.baltimorecity.gov/historic-districts/maps/butchershill", FALSE, TRUE,
"Dickeyville", "http://chap.baltimorecity.gov/historic-districts/maps/dickeyville", FALSE, TRUE,
"Eutaw Place/Madison Park", "http://chap.baltimorecity.gov/historic-districts/maps/eutawplaceandmadisonpark", FALSE, TRUE,
"Federal Hill", "http://chap.baltimorecity.gov/historic-districts/maps/federalhill", FALSE, TRUE,
"Fells Point", "http://chap.baltimorecity.gov/historic-districts/maps/fells-point", FALSE, TRUE,
"Five & Dime", "https://chap.baltimorecity.gov/five-and-dime-historic-district", FALSE, TRUE,
"Franklintown", "http://chap.baltimorecity.gov/historic-districts/maps/franklintower", FALSE, TRUE,
"Howard Street Commercial", "https://chap.baltimorecity.gov/howard-street-commercial-historic-district", FALSE, TRUE,
"Hunting Ridge", "http://chap.baltimorecity.gov/historic-districts/maps/huntingridge", FALSE, FALSE,
"Jonestown", "http://chap.baltimorecity.gov/historic-districts/maps/jonestown", FALSE, FALSE,
"Loft", "http://chap.baltimorecity.gov/historic-districts/maps/loft", FALSE, TRUE,
"Madison Park", "http://chap.baltimorecity.gov/historic-districts/maps/madisonpark", FALSE, TRUE,
"Mill Hill/Deck of Cards", "https://chap.baltimorecity.gov/historic-districts/maps/2600blockmillhilldeckofcardswilkinsave", FALSE, FALSE,
"Mount Royal Terrace", "http://chap.baltimorecity.gov/mount-royal-terrace", FALSE, TRUE,
"Mount Vernon", "http://chap.baltimorecity.gov/mount-vernon", FALSE, TRUE,
"Mount Washington", "http://chap.baltimorecity.gov/mount-washington", FALSE, FALSE,
"Oldtown Mall", "https://chap.baltimorecity.gov/oldtown-mall-historic-district", FALSE, FALSE,
"Otterbein", "http://chap.baltimorecity.gov/otterbein", TRUE, FALSE,
"Perlman Place", "http://chap.baltimorecity.gov/perlman-place", FALSE, FALSE,
"Railroad", "http://chap.baltimorecity.gov/railroad", FALSE, FALSE,
"Ridgely's Delight", "http://chap.baltimorecity.gov/rigleys-delight", FALSE, TRUE,
"Seton Hill", "http://chap.baltimorecity.gov/seton-hill", FALSE, TRUE,
"Sharp-Leadenhall", "https://chap.baltimorecity.gov/sharp-leadenhall", FALSE, FALSE,
"Stirling Street", "http://chap.baltimorecity.gov/stirling-street", FALSE, FALSE,
"Ten Hills", "http://chap.baltimorecity.gov/ten-hills", FALSE, FALSE,
"Union Square", "http://chap.baltimorecity.gov/union-square", FALSE, TRUE,
"Upton's Marble Hill", "http://chap.baltimorecity.gov/uptons-marble-hill", FALSE, TRUE,
"Washington Hill", "http://chap.baltimorecity.gov/washington-hill", FALSE, TRUE,
"Waverly", "http://chap.baltimorecity.gov/waverly", FALSE, FALSE,
"Woodberry", "http://chap.baltimorecity.gov/woodberry", FALSE, TRUE,
"Wyndhurst", "http://chap.baltimorecity.gov/wyndhurst", FALSE, FALSE
)
chap_districts <- chap_districts_geodata |>
dplyr::filter(stringr::str_detect(cha_pcode_ty, "^A")) |>
sfext::rename_sf_col() |>
dplyr::rename(name = area_name) |>
dplyr::mutate(
name = dplyr::case_when(
name == "Barclay/Greenmount - People's Homestead" ~ "Barclay/Greenmount",
name == "Eutaw Place/Madison Place" ~ "Eutaw Place/Madison Park",
name == "Mt. Royal Terrace" ~ "Mount Royal Terrace",
name == "Wilkens Avenue" ~ "Mill Hill/Deck of Cards",
.default = name
)
) |>
dplyr::left_join(chap_district_info, by = "name") |>
dplyr::mutate(
acres = as.numeric(units::set_units(sf::st_area(geometry), "acres"))
) |>
dplyr::select(
name,
contact_name = cntct_nme, url, deed_covenant, overlaps_nr_district, acres, geometry
)
usethis::use_data(chap_districts, overwrite = TRUE)
respagency_codes <- esri2sf::esrimeta("https://geodata.baltimorecity.gov/egis/rest/services/CityView/Realproperty/MapServer/0")
respagency_codes <- purrr::discard(respagency_codes[["fields"]][["domain"]][["codedValues"]], is.null)[[1]]
respagency_codes <- googlesheets4::read_sheet("https://docs.google.com/spreadsheets/d/1Dnyp4-AZxvFPpt5Vci4NRWR9tGP99R8RaHuPCbzcGCA/edit?usp=sharing")
respagency_codes <- respagency_codes |>
dplyr::mutate(
code = stringr::str_pad(code, width = 2, pad = "0")
)
usethis::use_data(respagency_codes, overwrite = TRUE)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.