Introduction

These visualizations from the New Jersey Construction Permit Dataset provide a thorough understanding of building trends, illustrating key patterns in permit issuance, fees collected, construction costs, and regional disparities.

The visualization emphasizes the dominance of alteration permits, growing construction costs in townships, and significant geographic differences in construction activity across the state.

Dataset

The original dataset was sourced from a public data archive of the state of New Jersey website.

Link: https://data.nj.gov/Reference-Data/NJ-Construction-Permit-Data/w9se-dmra/data_preview

In the initial and unaltered form of the dataset, there are around 2 million records, each with 47 variables . Each row represents a permit detail pulled for construction project in the state of New Jersey.

The dataset includes demographic data like City name, County name, Municipality name, Municipality Code, Municipality type. Also, it includes financial data like Building fee, Plumbing fee, Electrical fee, Fire fee, Elevator fee, Total fee, and Construction Cost, and few other variables like permit types, permit count, process date.

The original dataset contains records dating back to 1801, but this visualization focuses only on data from the past 10 years, covering the period from 2013 to 2023.

Load libraries

library(lubridate)
library(plyr)
library(scales)
library(dplyr)
library(ggplot2)
library(ggthemes)
library(ggrepel)
library(RColorBrewer)
library(plotly)

Findings

The following tabs offer comprehensive details about construction project permits issued in New Jersey from 2013 to 2023. They highlight the most commonly pulled permit types, the counties with the highest number of construction projects, and the municipality types with the most expensive projects.

Annual Construction Permit Counts in New Jersey (2013 - 2023)

Below histogram displays the number of construction project permits issued in New Jersey from 2013 to 2023. Here’s a breakdown of the key insights:

X-Axis (Year):

The years are represented from 2013 to 2023.

Y-Axis (Count of Permits):

The vertical axis represents the number of permits issued in each year.

Key Observations:

1. Steady Increase (2013–2018):

From 2013 to 2018, the number of permits gradually increased from 1,510 in 2013 to 5,231 in 2018. The growth is relatively slow during these years.

2. Significant Jump (2019–2021):

A sharp rise in permits occurs starting in 2019, reaching a peak of 45,528 permits in 2021. This significant increase indicates either a construction boom or changes in regulations/incentives that spiked more permit applications.

3. Decline (2022–2023):

After peaking in 2021, there’s a decline in 2022 and 2023, with 42,585 and 39,553 permits issued, respectively. Although it is still high compared to permits before 2019, this may indicate that the construction surge started to slow.

In summary, this histogram provides a clear view of trends in construction permits, showing both growth and a slight decline in the recent years.

# Create histogram of permit count by year

p1 <- ggplot(dframe10, aes(x=permit.year)) +
  geom_histogram(bins = 21, color = "red", fill = "lightblue") +
  labs(title = "Annual Construction Permit Counts in New Jersey (2013-2023)", x= "Year", y = "Count of Permits", caption = "Source: State of New Jersey  Website: www.nj.gov") + 
  theme(plot.title = element_text(hjust = 0.5)) +
  scale_y_continuous(labels=comma) + 
  stat_bin(binwidth = 1, geom = 'text', color = 'black', aes(label = scales::comma(after_stat(count))), vjust = -0.4)

x_axis_labels <- min(dframe10$permit.year, na.rm=TRUE):max(dframe10$permit.year, na.rm = TRUE)

p1 <- p1 + scale_x_continuous(labels = x_axis_labels, breaks = x_axis_labels, minor_breaks = NULL)

p1

Monthly Total Fees Collected for Building Alteration Projects in New Jersey

Below line plot represents the total fees collected by month for building alteration projects in the State of New Jersey.

X-Axis(Months):

The months are labeled from January to December, indicating a full year’s trend in fee collection by the state from 2013 to 2023.

Y-Axis(Total Fees):

The y-axis represents the total fees collected, ranging from $6 million to $9 million.

Key Observations:

1. Gradual Increase (January to June):

There is a steady increase in total fees collected from January to June, with a peak of $8.4 million in June. This could reflect a rising number of projects or higher-value projects being undertaken during the spring and early summer months.

2. Peak in June:

June is the highest point in the year for fees collected, with the highest fee collection amount of $8.4 million. This could be the result of a seasonal increase in construction or alterations, as the warmer months are typically more beneficial to construction work.

3. Gradual Decline (July to October):

After June, the total fees begin to slowly decrease through the summer, remaining somewhat steady from July to September, and then more significantly declining in October.

4. Sharp Decline (November and December):

From October to December, there’s a sharp drop in fees, ending at $6 million in December. This is a notable drop compared to the earlier months and may reflect seasonal (end of year) slowdown, as colder weather often slows down construction projects.

In summary, this line plot highlights a clear seasonal trend in building alteration fees, with activity ramping up in the middle of the year and slowing down towards the end of the year.

# Create line plot 

# Create new dataframe just with "Alteration" records.
PermitAlt_df <- dframe10[dframe10$Permit.Type.Description == "Alteration", ]

# Create new dataframe for line plot
month_df <- PermitAlt_df %>%
  select(Permit.Date, Total.Fee, Permit.Type.Description) %>%
  mutate(months12 = month(mdy(Permit.Date), label = TRUE)) %>%
  group_by(months12, Permit.Type.Description) %>%
  summarise(total_fee = sum(Total.Fee), .groups = 'keep') %>%
  data.frame()

max_y <- round_any(max(month_df$total_fee)/1000000, 1, ceiling)
ylab <- seq(1, max_y, 1 )
y_axis_labels <- paste0("$", ylab, "M")


hi_low <- month_df %>%
  filter(total_fee == min(total_fee) | total_fee == max(total_fee)) %>%
  data.frame()

# Create month order
month_order <- factor(month_df$months12, 
                    level=c('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug',  'Sep', 'Oct', 'Nov', 'Dec'))

x_axis_labels <- min(month_df$months12) : max(month_df$months12)


ggplot(month_df, aes(x = month_order, y = total_fee, group = Permit.Type.Description)) +
  geom_line(color = 'black', linewidth = 1) +
  geom_point(shape =21, size = 4, color = "red", fill = "white") +
  labs(x = "Months", y = "Total Fees  (in millions)", title = "Monthly Total Fees Collected for Building Alteration Projects in New Jersey", 
       caption = "Source: State of New Jersey  Website: www.nj.gov", color = "Construction Type") +
  scale_y_continuous(labels = y_axis_labels, breaks = ylab*1000000, minor_breaks = NULL) +
  theme_light() +
  theme(plot.title = element_text(hjust = 0.5)) + 
  geom_point(data = hi_low, aes(x = months12, y = total_fee), 
             shape = 21, size=4, fill = 'red', color = 'red') +
  geom_label_repel(aes(label = ifelse(total_fee == max(total_fee) | 
                                        total_fee == min(total_fee),
                                      paste0("$", round(total_fee/1000000, 1), "M"), "")), box.padding = 1, point.padding = 1, size = 4, color = 'Grey50', segment.color = 'darkblue')

Annual Construction Costs in New Jersey by Municipality Type (2013 - 2023)

The multiple line plot displays construction costs over time (2013–2023) across different municipality types in New Jersey, with costs shown in millions of dollars.

X-Axis (Year):

The years range from 2013 to 2023, illustrating the timeline of construction costs.

Y-Axis (Construction Cost in Millions):

The y-axis shows construction costs, ranging from $0 to approximately $1 billion.

Key Observations:

1. Significant Growth (2017–2021):

Most municipality types show a sharp increase in construction costs beginning around 2017 or 2018, with the Township category (green line) leading the way, reaching a peak of $985.5 million in 2021.

Cities, Towns, and Boroughs also show substantial increases in construction costs between 2017 and 2021, though not as huge as townships.

2. Township Dominance:

Townships (green line) consistently have the highest construction costs, especially from 2019 to 2023. They reach their peak in 2021 at $985.5 million, but even in 2022 and 2023, they remain well above the other categories.

3. Post-2021 Decline:

Across most categories, there is a general decline in construction costs after 2021, though townships remain relatively high even in 2023, whereas towns and cities show sharper reductions in costs after 2021.

In summary, this plot gives a clear indication of how different types of municipalities experienced varying trends in construction activity, with townships consistently dominating the construction projects.

# Create multiple line plot

# Create year data frame
year_df <- dframe10 %>%
  select(permit.year, Construction.Cost, MuniType) %>%
  mutate(year = as.factor(permit.year)) %>%
  group_by(year, MuniType ) %>%
  summarise(Construction_cost = sum(Construction.Cost), .groups = 'keep') %>%
  data.frame()

# Create y axis label
max_y <- round_any(max(year_df$Construction_cost)/1000000, 1000000000, ceiling)
ylab <- seq(100000000, max_y, 100000000)
y_axis_labels <- paste0("$", ylab/1000000, "M")

ggplot(year_df, aes(x = year, y = Construction_cost, group = MuniType)) +
  geom_line(aes(color = MuniType), linewidth = 2) +
  labs(title = "Annual Construction Costs in New Jersey by Municipality Type", 
       x = "Year", y = "Construction Cost  (in millions)", 
       caption = "Source: State of New Jersey  Website: www.nj.gov") +
  theme_light() +
  theme(plot.title = element_text(hjust = 0.5)) +
  geom_point(shape = 21, size = 2, color = "black", fill = "white") +
    geom_label_repel(aes(label = ifelse(Construction_cost == max(Construction_cost),
                                      paste0("$", round(Construction_cost/1000000, 1), "M"), "")),
                     box.padding = 1, 
                     point.padding = 1, 
                     size = 4, 
                     color = 'Grey50', 
                     segment.color = 'darkblue') +
    scale_x_discrete(guide = guide_axis(angle = 45)) +
    scale_y_continuous(labels = y_axis_labels, breaks = ylab, minor_breaks = NULL) +
  scale_color_brewer(palette ="Set2", name = "Municipality Type", guide = guide_legend(reverse = TRUE))

Permit Type Distribution in New Jersey Townships by Year (2018 - 2023)

Below pie charts represent the distribution of permit types by year from 2018 to 2023. The permit types are divided into four categories:

1. Alteration (blue)
2. New (orange)
3. Addition (green)
4. Demolition (red)

Key Observations:

Dominance of Alteration Permits:

Across all years (2018–2023), the alteration permit type dominates the distribution, consistently representing over 84% of all permits.

New Construction Permits:

The second largest category is new permits (orange), which remains fairly stable over the years but shows a slight decline, dropping from 8.1% in 2018 to 4.7% in 2023.

Additions and Demolitions:

Addition permits (green) and demolition permits (red) make up much smaller portions of the total. Both categories maintain low, fairly stable percentages across the years.

Overall, this series of pie charts illustrates a trend where alterations are the predominant activity in the construction projects.

# Create pie charts

# Create permit type dataframe

Permit_type_df <- dframe10 %>%
  select(permit.year, Permit.Type.Description, MuniType) %>%
  mutate(year = as.factor(permit.year)) %>%
  group_by(year, Permit.Type.Description, MuniType) %>%
  summarise(n = length(Permit.Type.Description), .groups = 'keep') %>%
  data.frame()

last6year <- c(2018, 2019, 2020, 2021, 2022, 2023)

Permit_type_df$Permit.Type.Description = factor(Permit_type_df$Permit.Type.Description, levels = c("Addition", "Alteration", "Demolition", "New"))

# Create data frame with only last 6 year of data and Township municipality

Permit_type_df <- Permit_type_df[Permit_type_df$year %in% last6year & Permit_type_df$MuniType == "TOWNSHIP",]

plot_ly(textposition = "inside", labels = ~Permit.Type.Description, values = ~n) %>%
  add_pie(data = Permit_type_df[Permit_type_df$year == 2018,],
          name = "2018",
          title = "2018",
          domain=list(
            row = 0,
            column = 0)
          ) %>%
  layout(title = "Permit Type Distribution in New Jersey Townships by Year",
         showlegend = TRUE, 
         grid = list(rows = 2, columns = 3)) %>%
    add_pie(data = Permit_type_df[Permit_type_df$year == 2019,],
          name = "2019",
          title = "2019",
          textposition = "inside",
          domain=list(
            row = 0,
            column = 1)
          ) %>%
      add_pie(data = Permit_type_df[Permit_type_df$year == 2020,],
          name = "2020",
          title = "2020",
          textposition = "inside",
          domain=list(
            row = 0,
            column = 2)
          ) %>%
    add_pie(data = Permit_type_df[Permit_type_df$year == 2021,],
          name = "2021",
          title = "2021",
          textposition = "inside",
          domain=list(
            row = 1,
            column = 0)
          ) %>%
    add_pie(data = Permit_type_df[Permit_type_df$year == 2022,],
          name = "2022",
          title = "2022",
          textposition = "inside",
          domain=list(
            row = 1,
            column = 1)
          ) %>%
      add_pie(data = Permit_type_df[Permit_type_df$year == 2023,],
          name = "2023",
          title = "2023",
          textposition = "inside",
          domain=list(
            row = 1,
            column = 2)
          ) 

Permit Count in New Jersey by County and Year (2018 - 2023)

The heatmap displays the permit count by county and year from 2018 to 2023 across various counties in New Jersey. Darker shades of red represent higher permit counts, while lighter shades indicate fewer permits.

X-Axis (Year):

The timeline spans from 2018 to 2023, showing the yearly distribution of permits.

Y-Axis (County):

The y-axis lists the counties in New Jersey.

Key Observations:

High Permit Activity in Specific Counties:

The counties with the darkest red consistently across most years include:

- Bergen
- Burlington
- Morris
- Ocean

These counties had the highest permit activity, with numbers ranging from 3,400 to over 4,700 permits annually.

Bergen County shows the highest permit counts, peaking at 4,785 permits in 2021 and staying above 4,000 in following years. This suggests that Bergen county has more developments going around in the state of New Jersey as compared to other counties.

Peaks in 2021 and 2022:

Several counties show a significant spike in permit activity in 2021 and 2022. This could be attributed to post-pandemic economic recovery, infrastructure investment, or a surge in housing demand.

In summary, this heatmap provides a visual representation of how construction permit activity varies widely across New Jersey, with certain counties showing sustained high activity and others remaining much quieter over the years.

# Create heat map

# Create permit dataframe

permit_df <- dframe10 %>%
  select(permit.year, County) %>%
  mutate(County = factor(County, levels = sort(unique(County), decreasing = TRUE))) %>%
  mutate(year = as.factor(permit.year)) %>%
  group_by(year, County) %>%
  summarise(Permit_Count = length(year), .groups = 'keep') %>%
  data.frame()

# Exclude that one record with state wide project.

permit_df <- permit_df[permit_df$County != "STATE",]

last6year <- c(2018, 2019, 2020, 2021, 2022, 2023)


# Keep only last 6 year of data
permit_df <- permit_df[permit_df$year %in% last6year,]

breaks <- c(seq(0, max(permit_df$Permit_Count), by=1000))


g <- ggplot(permit_df, aes(x = year, y = County, fill = Permit_Count )) +
  geom_tile(color = "black") +
  geom_text(aes(label = comma(Permit_Count))) +
  coord_equal(ratio = 0.25) +
  labs(title = "Permit Count in New Jersey by County and Year",
       x = "Year",
       y = "County",
       fill = "Permit count", caption = "Source: State of New Jersey  Website: www.nj.gov") + 
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5)) +
  scale_fill_continuous(low="white", high = "red", labels = comma, breaks = breaks) +
  guides(fill = guide_legend(reverse = TRUE, override.aes = list(colour="black")))

ggplotly(g, tooltip = c("Permit_Count", "year", "County")) %>%
  style(hoverlabel = list(bgcolor = "white"))

Permit Count in New Jersey by County and Year (2018 - 2023)

The stacked bar chart shows the number of permits issued in various counties over the past 6 years ranging from 2018 to 2023. Each bar represents a county, and the different colored segments within the bars represent permit counts for different years.

X-Axis

Displays the permit count ranging from 0 to 16,000.

Y-axis

Displays the counties under the municipality type ‘Township’.

Each bar is stacked with different colored segments, each representing a different year ranging from 2018 to 2023.

Key observations:

Overall trend:

The permit count for most counties has increased from 2018 to 2023.

Top counties: Ocean County has the highest number of permits for all the years, followed by Middlesex and Monmouth counties in the township municipality.

Year-over-year changes:* The increase in permit count is mostly prominent for Ocean and Middlesex counties, especially between 2021 and 2022.

County-specific trends: Some counties, such as Hudson and Cumberland, have experienced relatively smaller increases in permit count.

Overall, the chart indicates a general upward trend in permit issuance across New Jersey counties over the past few years. However, there are variations among counties, suggesting that factors such as economic conditions, development regulations, and population growth may influence permit activity differently in each region.

# Create stacked bar chart

# Create permit county data frame
Permit_county_df <- dframe10 %>%
  select(permit.year, County, MuniType) %>%
  mutate(year = as.factor(permit.year)) %>%
  group_by(year, MuniType, County) %>%
  summarise(n = length(year), .groups = 'keep') %>%
  data.frame()

last6year <- c(2018, 2019, 2020, 2021, 2022, 2023)

# Keep only last 6 year of data and Township municipality
Permit_county_df <- Permit_county_df[Permit_county_df$year %in% last6year & Permit_county_df$MuniType == "TOWNSHIP",]

# Create county dataframe based on total permits 
Permit_county_tot <- Permit_county_df %>%
  select(County, n) %>%
  group_by(County) %>%
  summarise(Total = sum(n), .groups = 'keep') %>%
  data.frame()

# Create y axis maximum limit
max_y <- plyr::round_any(max(Permit_county_tot$Total), 18000, ceiling)

ggplot(Permit_county_df, aes(x = reorder(County, n, sum), y = n, fill = year)) +
  geom_bar(stat = "identity", position = position_stack(reverse = TRUE)) +
  coord_flip() +
  labs(title = "Permit Count in New Jersey by County and Year", x = "County", y="Permit Count", fill = "Year") +
  theme_light() + 
  theme(plot.title = element_text(hjust = 0.5)) +
  scale_fill_brewer(palette =  "Paired", guide = guide_legend(reverse = TRUE)) +
  geom_text(data = Permit_county_tot, aes(x = County, y = Total, label = scales::comma(Total), fill = NULL), hjust = -0.1, size = 4) +
  scale_y_continuous(labels = comma, 
                     breaks = seq(0, max_y, by = 4000), 
                     limits = c(0, max_y))

Conclusion

These visualizations suggest that the New Jersey construction sector experienced substantial growth between 2019 and 2021, driven by increased residential and commercial developments, particularly in suburban townships.

Alteration projects dominated, indicating a strong preference for upgrading existing buildings over new construction. Regional disparities highlight that certain counties, especially Bergen, Monmouth, and Burlington, are construction hotspots, while others see much less activity.

The pandemic acted as both a challenge and a catalyst, leading to a boom in construction projects, though this momentum has slightly declined in the last couple of years.