The purpose of the following analysis was to explore some of the characteristics of residential construction permits for the City of Seattle that have been issued so far in 2023. This initial overview was done to find some key factors related to location and type of permits issued, the number of new units to be added, along with the associated permit value of the projects. There were four different maps created, each looking at the data in a different manner.
library(sf)
library(tidyverse)
library(rgdal)
library(scales)
library(RColorBrewer)
library(units)
library(cowplot)
library(here)
library(leaflet)
library(leafem)
library(leafpop)
The first steps taken were related to data acquisition and preparation. The data set I used contains data for residential construction permits since 2010, that can be found through the Seattle GeoData portal as Built Units Since 2010. In addition to the associated coordinates and addresses for each permit, there are numerous attributes related to property type, units to be added or demolished, permit value, neighborhood, and several others. After obtaining the CSV files, I selected only permits issued in 2013 with a net addition of units. I also only selected a few variables to be used for further analysis and renamed some columns. Once complete, the coordinate variables were used to create a simple feature object. The following steps outline the process.
permits <- read_csv(here("Data","Seattle_Permits.csv")) %>% # Read in file
drop_na(LONGITUDE) %>% # Remove rows with N/A for coordinates
filter(YEAR_ISSUED >= 2023 & NET_UNITS >0) %>% # Only select permits for current year with net new units added
select(OBJECTID, LOT_SIZE, PRMT_NR,NET_UNITS,VALUE,TYPE_OCC,YEAR_ISSUED,CRA,NEIGHBORHOOD,LONGITUDE,LATITUDE) %>% # Only retain relevant columns
rename("Permit" = PRMT_NR, "New_Units" = NET_UNITS,"Unit_Type" = TYPE_OCC, "Neigborhood" = CRA, "District" = NEIGHBORHOOD, "value" = VALUE) # Rename some columns
glimpse(permits)
## Rows: 446
## Columns: 11
## $ OBJECTID <dbl> 5150, 5168, 5331, 5369, 5378, 5385, 5386, 5389, 5390, 5487…
## $ LOT_SIZE <dbl> 6924, 7333, 51124, 7571, 13348, 3436, 3436, 3416, 3416, 50…
## $ Permit <dbl> 6930747, 6888945, 6857761, 6786325, 6735916, 6884794, 6884…
## $ New_Units <dbl> 1, 1, 238, 1, 89, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1…
## $ value <dbl> 235100, 761427, 47400135, 193281, 11285988, 447194, 447194…
## $ Unit_Type <chr> "DADU", "ADU", "MIXED", "SF", "MIXED", "SF", "ADU", "SF", …
## $ YEAR_ISSUED <dbl> 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023, 2023…
## $ Neigborhood <chr> "Madison Park", "Cedar Park/Meadowbrook", "Ballard", "Nort…
## $ District <chr> "East", "North", "Ballard", "Ballard", "North", "Central",…
## $ LONGITUDE <dbl> -122.2906, -122.2778, -122.3871, -122.3603, -122.3211, -12…
## $ LATITUDE <dbl> 47.62869, 47.70718, 47.66884, 47.70810, 47.71032, 47.61201…
permit_pts <- st_as_sf(permits, coords = c("LONGITUDE","LATITUDE"), crs = 3690) # Convert to sf
unit_type <- permits$Unit_Type # Select Unit type columns
types <- as.data.frame(unique(unit_type)) # Obtain list of different unit types
types # Display results
## unique(unit_type)
## 1 DADU
## 2 ADU
## 3 MIXED
## 4 SF
## 5 MF
color_pal <- colorFactor(c("lightgreen","darkgreen","darkblue","orange","lightblue"),
domain = c("DADU","ADU","MIXED","SF","MF")) # Create color palette to assign colors based on unit type
The first map shown in Figure 1 below provides the location of each permit in the data set, along with a popup table containing related attribute information.
leaflet(data = permit_pts) %>%
setView(lng = -122.335167, lat = 47.608013, zoom = 11) %>% # Center on city center
addProviderTiles(providers$CartoDB.DarkMatter) %>% # Add basemap
addProviderTiles(providers$Stamen.TonerLines, options = providerTileOptions(opacity = .20)) %>% # Add roads as separate layer
addCircleMarkers(color = "darkred", fillOpacity = .75, stroke = F,
popup = leafpop::popupTable(st_drop_geometry(permit_pts[,2:9]),feature.id = F,
row.numbers = F), radius = 4) %>% # Add markers with popup table
addScaleBar(position = "bottomright") %>% # Add scale bar
addMiniMap() # Add mini-map
Figure 1: Location of constuction permits issued in 2023 with popup tables
The second map shows the location of issued permits with colors based on unit type and can be seen in Figure 2. Green colors are for Accessory Dwelling Units (ADUs), blue colors for single-family (sf) and multi-family (mf) residences, and orange for mixed-use (mixed). The location of the different unit types is more easily observed on this map. ADUs appear to be the most prominent unit type for which permits have been obtained. Multi-family permits also seem to be prominent, along with mixed-use permits. These unit types appear to be found predominantly near major roadways. There are also single-family permits scattered throughout.
pop <- paste0(permit_pts$New_Units," New Units Added") # popup message with associated value for number of units
leaflet() %>%
setView(lng = -122.335167, lat = 47.608013, zoom = 11) %>% # Center on city center
addProviderTiles(providers$CartoDB.Voyager) %>% # Add basemap
addProviderTiles(providers$Stamen.TonerLines, options = providerTileOptions(opacity = .20)) %>% # Add roads as separate layer
addCircleMarkers(data = permit_pts, color = ~color_pal(Unit_Type),label = ~Unit_Type, popup = pop, radius = 5) %>% # Add markers that are color coded based on unit type with popup displaying unit count
addScaleBar(position = "bottomright") %>% # Add scale bar
addLegend("bottomleft",
colors = c("lightgreen","darkgreen","orange","lightblue","darkblue"),
labels =c("ADU","DADU","MIXED","SF","MF"),
title = "Unit Type") %>% # Add legend that displays unit type and corresponding color
addMiniMap() # Add mini-map
Figure 2: Location of permits issued in 2023, color coded based on unit type
Figure 3 scales the symbols based on new units added. Mixed-use permits are responsible for the greatest number of new units added, at least on a per permit basis, with a multi-family permit also adding a substantial number of new units. These properties are also found predominantly in two main locations, in the northwest section of the City, and the southeast section.
leaflet() %>%
setView(lng = -122.335167, lat = 47.608013, zoom = 11) %>% # Center on city center
addProviderTiles(providers$CartoDB) %>% # Add basemap
addProviderTiles(providers$Stamen.TonerLines, options = providerTileOptions(opacity = .20)) %>% # Add roads as separate layer
addCircles(data = permit_pts, fillColor = ~color_pal(Unit_Type),
color = NA, fillOpacity = 0.75, radius = ~New_Units*5, label = ~Unit_Type, popup = pop) %>% # Add circles that are scaled based on new units added with popup displaying new units added
addScaleBar(position = "bottomright") %>% # Add scale bar
addLegend("bottomleft",
colors = c("lightgreen","darkgreen","orange","lightblue","darkblue"),
labels =c("ADU","DADU","MIXED","SF","MF"),
title = "Unit Type") %>% # Add legend that displays unit type and corresponding color
addMiniMap() # Add mini-map
Figure 3: Location of permits issued in 2023 with symbols scaled based on number of new units per permit
The final map created, and can be found in Figure 4, scales the symbols based on permit value. The main takeaways are like what was found with the unit count map, but one permit stands out as truly unique in this map. The largest symbol by far, shown in dark red, is significantly greater in size and darker in color than any other symbol. If not for the size, it would be hard to tell a difference in values between all the other permits and the largest one shown. This mixed-use property is really in a league of its own, at least based on permits issued this year.
pop2 <- paste0("Value of Project - $ ",permit_pts$value) # popup message
pal <- colorNumeric(palette = "YlOrRd",domain = permit_pts$value) # Color scale to be used
leaflet(data = permit_pts) %>%
setView(lng = -122.335167, lat = 47.608013, zoom = 11) %>% # Center on city center
addProviderTiles(providers$CartoDB.DarkMatter) %>% # Add basemap
addProviderTiles(providers$Stamen.TonerLines, options = providerTileOptions(opacity = .20)) %>% # Add roads as separate layer
addCircles(fillColor = ~colorNumeric("YlOrRd", value)(value),
color = NA, fillOpacity = 0.75, radius = ~value/25000,
label = ~Unit_Type, popup = pop2) %>% # Add circles that scale based on permit value with popup displaying permit value
addScaleBar(position = "bottomright") %>% # Add scale bar
addLegend("bottomleft", pal = pal, values = ~value, title = "Permit Values", opacity = 1,labFormat = labelFormat(prefix = "$ ")) %>% # Add legend that shows range of permit values and corresponding colors
addMiniMap() # Add mini-map
Figure 4: Location of permits issued in 2023 with symbols scaled based on permit value
Based on the analysis, there are several main summary results. One, is that accessory dwelling units seem to be the most common unit type for permits issued this year, and that the multi-family and mixed-use buildings appear to be concentrated near main transportation nodes. Another takeaway is that in terms of new units to be added on a per permit basis, mixed-use properties are responsible for the highest number. Finally, the value of the projects varies significantly from the highest value to the lowest value. There is one project that has a value that is so much greater than the others, it is hard to know whether that property is that much larger or if there is a data error. Further follow-up steps would be to clarify whether that one permit value is correct or not, and to determine if there are multiple permits for one project. The data used was based on permit numbers, not addresses. It is possible that one project contains multiple permits. If that is the case, then the scale of some of the properties in relation to one another would change. These are the suggested follow-up steps based on the conclusion through this previously discussed analysis.