The economic impact of climate change on coral reef in the Main Hawaiian Islands
Author
Ashley Lowe Mackenzie et. al
Coral Reef Hawaii
The following code estimates welfare changes associated with varying conditions of nearshore environmental quality on the island of Hawai’i. The primary impact considered is the loss of coral reef biomass, which serves as an environmental and economic asset. Welfare effects are estimated through two distinct models that capture changes in household utility and behavioral responses to environmental degradation. These models use observed visitation and population data to approximate demand, and they translate changes in reef quality into utility impacts, following standard approaches in environmental and recreational economics. The two models include:
An Economic Model using a random utility framework from Fezzi. et al 2023
Atlantic Biophysical Sub-Model which estimates changes to ecological conditions.
The graphical representation of this process is illustrated below
Running Code
This section calls the necessary R packages and sources external scripts from the original study. These scripts provide the estimated coefficients from the Random Utility Model (RUM), which will be used to simulate individual preferences and estimate welfare changes under different environmental quality scenarios. These parameters reflect the marginal utility of various site attributes, including coral reef biomass, travel cost, and environmental conditions.
Show code
library(sf)library(dplyr)library(tidyr)library(ggplot2)library(sf)library(gganimate)### load functionsgetwd()source("codedata/dummier.R")source("codedata/travel_cost.R")source("codedata/gridplot.R")### load model ###load(file ="codedata/model3.mod")### this are the travel cost model estimates ###m1
Atlantis Model
To assess environmental changes in the nearshore ecosystem, we incorporate biomass outputs from the Atlantis ecosystem model. These outputs represent projected ecological dynamics—specifically, coral reef and associated species biomass—under different management and environmental scenarios.
The biomass values will be:
Spatially aggregated by polygon to match the resolution used in the economic model.
Processed annually to calculate percentage changes in biomass relative to the baseline year.
These percentage changes provide the key environmental quality metric (e.g., reef health) that feeds into the Economic Model outlined in the previous section. Specifically, the estimated changes will modify site attributes within the Random Utility Model framework to simulate how changes in reef biomass affect recreational behavior and welfare.
Base level Coral
The base level of coral is the average biomass of 2015-2020 for each near polygon.
Yearly Relative Change
Then for each time step out to 2100 we sum up the biomass of coral reef:
\(C_{pt} = \sum V_{pt} / \sum V_{pt}=0\)
The following code does this for scenario SSP1 1-3. This looks at the relative change of coral biomass within each polygon in the nearshore environment.
This shows the overall predicted relative change in coral cover across each scenario.
Show code
coral_graph <- coral_graph %>%mutate(time_step =as.numeric(gsub("time", "", time)) +2006 ) %>%filter(time_step <=2100)coral1=coral_graph %>%group_by(SSP, time_step) %>%summarize(mean_coral=mean(Coral_perchange)) group.colors <-c(SSP1 ="royalblue",SSP2 ="springgreen",SSP3 ="deeppink")coral1$percentage=coral1$mean_coral-1ggplot(coral1, aes(x = time_step, y = percentage, color = SSP)) +geom_point(alpha =0.3) +# optional: show raw meansgeom_smooth(method ="loess", se =TRUE, aes(fill = SSP), alpha =0.2) +scale_color_manual(values = group.colors) +scale_fill_manual(values = group.colors) +theme_minimal() +theme(text =element_text(family ="Times New Roman"),plot.title =element_text(hjust =0.5),legend.position ="bottom",legend.background =element_rect(fill ="white") ) +labs(title ="Projected Change in Coral Cover By SSPs",x ="Year",y ="Relative Change Coral Cover",color ="SSP" ) +theme_minimal(base_size =14) +theme(text =element_text(family ="Times New Roman"), plot.title =element_text(hjust =0.5), legend.position ="bottom", legend.title =element_text(family ="Times New Roman"),legend.text =element_text(family ="Times New Roman") )ggsave('images/avercoral_scenario.png', dpi =300, height =5, width =8, unit ='in')
Population
The following code shows the predicted change in population under scenario SSP1 1-3 using the data available for state of Hawaii Zoraghein et al. (2020)
Show code
library(readxl)pop<-read_excel("codedata/population_Zoragheinetal2020.xlsx")pop$Population=as.numeric(pop$Population)pop=pop %>%group_by(Scenario) %>%mutate(BasePop = Population[Year ==2020],Population_weight = (Population) / BasePop ) %>%ungroup()pop <- pop %>%mutate(across(c( Scenario), toupper))pop=subset(pop, Scenario!="SSP5"& Scenario!="SSP4")group.colors <-c(SSP1 ="royalblue",SSP2 ="springgreen",SSP3 ="deeppink")ggplot(pop, aes(x = Year, y = Population/1000000, color = Scenario, group = Scenario)) +geom_line(size =1.2) +scale_color_manual(values = group.colors) +labs(title ="Population Growth By SSPs in Hawaii",x ="Year",y ="Population in Millions",color ="Scenario" ) +theme_minimal(base_size =14) +theme(text =element_text(family ="Times New Roman"), plot.title =element_text(hjust =0.5), legend.position ="bottom", legend.title =element_text(family ="Times New Roman"),legend.text =element_text(family ="Times New Roman") )ggsave('images/population_scenario.png', dpi =300, height =5, width =8, unit ='in')
Travel Cost
The following code calculates the travel cost from each residential grid to each recreation site across the Hawaiian Islands. It uses economic and geographic data collected from each island, including household income, travel distance, and mode assumptions.
Travel costs are estimated following the methodology of Fezzi et al. (2023), who incorporate both time and monetary expenses into a unified measure of generalized cost. These estimates serve as one of the key explanatory variables in the Random Utility Model (RUM), which is used to simulate recreation site choice.
Prediction Model
For each scenario predicted by the Atlantis ecosystem model (e.g., SSP1, SSP2, SSP3), we run a simulation loop across all time steps to estimate the welfare impacts of changing nearshore coral biomass.
Specifically, for each year in the scenario:
Biomass outputs are aggregated spatially (by polygon or site).
The percentage change in coral reef biomass relative to the baseline is calculated.
These changes are passed into the Random Utility Model, updating site attributes for each grid-cell household.
Compensating Variation (CV) is then computed to measure the change in household welfare due to environmental change.
This process is repeated for each:
Grid cell (representing origin locations of visitors)
Recreational site (destination choices)
Time step (e.g., yearly from 2025 to 2100)
Scenario (SSP1–3)
Predict SSP1
Below is a loop (conceptual or in code) that:
Iterates through each time step of the SSP1 scenario
Updates coral biomass conditions
Recalculates utilities and choice probabilities
Estimates welfare change (CV) for each grid-location pair
Show code
### parametersx1 <-readRDS("codedata/x1.rds")x1$coastal[x1$name =="Home"]=0### Prepared dataset for maps plot:out <- x1[order(x1$siteID),]out <- out[c(1,3,8:12)]out=out[!duplicated(out[2]),]##using 85K because that was the survey amountout$incometran_track=out$medincome_tract/85000sites_join <-read.csv("codedata/sites_join.csv")coasts <- sites_join[sites_join$coastal ==1& sites_join$name!="Home",]x1=merge(SSP1, x1, by.x ="polygon", by.y ="Box_ID_2", all.y =TRUE)x1 <- x1[order(x1$km2_ID,x1$siteID),] ## btw it is correct that the dim(x) is lower than dim(dist) because## I aggregated some siteslength(unique(x1$siteID))### FINISHED LOADING AND MERGING DATASETS ####rm(dist, pop, sitesjoin)### CALCULATE TRAVEL COST ####x1$cost <-0x1$duration[ x1$siteID ==351] <- x1$duration[ x1$siteID ==351] +40## this sites needs 40min walking to be reached## Need to also do this for Hawaii### Change here for different fuel costx1$cost <- x1$distance.meters*0.001* (0.20/1.5 ) ## fuel cost ## assumption on fuel cost:## 20 miles/gallon# $4.3/gallon# means $4.3 per 20 miles --> 0.215 $/mile# 10 km --> 6.2 miles --> $1.33 travel cost per km# 10km * 0.20 / 1.5 = $1.33 so the values coincide with the cost used above.x1$cost <- x1$cost + (x1$duration /60)*3/4*24.4## add the value of time (assuming a 25$ per hour average wage rate)x1$cost <- x1$cost *2## the value for a return trip#### put Molokini cost equal to the one of Makena Landing Beach Park + 100$ (cost of a snorkeling tour)x1$cost[x1$siteID ==388] <- x1$cost[x1$siteID ==359] +100beta <- m1$results[,1]X0 <-cbind( x1$cost,x1$home, x1$coastal, x1$citypark, x1$trailall, x1$haleakala, x1$molokini, x1$parking, x1$showers, x1$lifeguard, x1$rock, x1$manmade, x1$beachmedium, x1$beachlarge, x1$surf, x1$swim, x1$snork, x1$res_fish_bio, x1$PNAS, x1$playground, x1$sports, x1$snork*x1$PNAS, x1$snork*x1$res_fish_bio)X0[is.na(X0)] <-0xsim <- x1final <-data.frame(matrix(ncol =2, nrow =0))all <-data.frame(matrix(ncol =2, nrow =0))#colnames(final) <- c("time10", "time20" , "time30" , "time40")#this needs to be ran as a loopfor (i in2:82) { xsim <- x1 xsim$PNAS <- xsim$PNAS *xsim[,i] xsim$PNAS[xsim$PNAS <=0] <-0 X1 <-cbind( xsim$cost,xsim$home, xsim$coastal, xsim$citypark, xsim$trailall, xsim$haleakala, xsim$molokini, xsim$parking, xsim$showers, xsim$lifeguard, xsim$rock, xsim$manmade, xsim$beachmedium, xsim$beachlarge, xsim$surf, xsim$swim, xsim$snork, xsim$res_fish_bio, xsim$PNAS, xsim$playground, xsim$sports, xsim$snork*xsim$PNAS, xsim$snork*xsim$res_fish_bio) X1[is.na(X1)] <-0### CALCULATION OF WTP FOR EACH GRID LOCATION wtpw <-quality.change(beta = beta, ### parametersX0=X0, ### X variables in the baselineX1 = X1, #### X variables in the scenariopid = x1$km2_ID, ### ID of the 1km gridcost =1) ### column of the cost parameter in the X matrix### TOTAL WTP b=merge(wtpw,out, by.x=c("id"),by.y=c("km2_ID")) b$time=i a=b %>%group_by(island) %>%summarize(SSP1_block=sum(WTP *grid_km_censusblock_Pop18_densityKM *365) ) a$time=i all=rbind(b,all) final=rbind(a,final)}df=finalall_df=allcolnames(all_df)[2]="SSP1"
Predict SSP2
Show code
x1 <-readRDS("codedata/x1.rds")x1=merge(SSP2, x1, by.x ="polygon", by.y ="Box_ID_2", all.y =TRUE)x1 <- x1[order(x1$km2_ID,x1$siteID),] ## btw it is correct that the dim(x) is lower than dim(dist) because## I aggregated some siteslength(unique(x1$siteID))### FINISHED LOADING AND MERGING DATASETS ####rm(dist, pop, sitesjoin)### CALCULATE TRAVEL COST ####x1$cost <-0x1$duration[ x1$siteID ==351] <- x1$duration[ x1$siteID ==351] +40## this sites needs 40min walking to be reached## Need to also do this for Hawaii### Change here for different fuel costx1$cost <- x1$distance.meters*0.001* (0.20/1.5 ) ## fuel cost ## assumption on fuel cost:## 20 miles/gallon# $4.3/gallon# means $4.3 per 20 miles --> 0.215 $/mile# 10 km --> 6.2 miles --> $1.33 travel cost per km# 10km * 0.20 / 1.5 = $1.33 so the values coincide with the cost used above.x1$cost <- x1$cost + (x1$duration /60)*3/4*24.4x1$cost <- x1$cost *2## the value for a return trip#### put Molokini cost equal to the one of Makena Landing Beach Park + 100$ (cost of a snorkeling tour)x1$cost[x1$siteID ==388] <- x1$cost[x1$siteID ==359] +100### PREPARE DATA FOR PREDICTIONS ### parametersbeta <- m1$results[,1]X0 <-cbind( x1$cost,x1$home, x1$coastal, x1$citypark, x1$trailall, x1$haleakala, x1$molokini, x1$parking, x1$showers, x1$lifeguard, x1$rock, x1$manmade, x1$beachmedium, x1$beachlarge, x1$surf, x1$swim, x1$snork, x1$res_fish_bio, x1$PNAS, x1$playground, x1$sports, x1$snork*x1$PNAS, x1$snork*x1$res_fish_bio)X0[is.na(X0)] <-0xsim <- x1final <-data.frame(matrix(ncol =2, nrow =0))all <-data.frame(matrix(ncol =2, nrow =0))#colnames(final) <- c("time10", "time20" , "time30" , "time40")#this needs to be ran as a loopfor (i in2:83) { xsim <- x1 xsim$PNAS <- xsim$PNAS *xsim[,i] xsim$PNAS[xsim$PNAS <=0] <-0 X1 <-cbind( xsim$cost,xsim$home, xsim$coastal, xsim$citypark, xsim$trailall, xsim$haleakala, xsim$molokini, xsim$parking, xsim$showers, xsim$lifeguard, xsim$rock, xsim$manmade, xsim$beachmedium, xsim$beachlarge, xsim$surf, xsim$swim, xsim$snork, xsim$res_fish_bio, xsim$PNAS, xsim$playground, xsim$sports, xsim$snork*xsim$PNAS, xsim$snork*xsim$res_fish_bio) X1[is.na(X1)] <-0### CALCULATION OF WTP FOR EACH GRID LOCATION wtpw <-quality.change(beta = beta, ### parametersX0=X0, ### X variables in the baselineX1 = X1, #### X variables in the scenariopid = x1$km2_ID, ### ID of the 1km gridcost =1) ### column of the cost parameter in the X matrix### TOTAL WTP b=merge(wtpw,out, by.x=c("id"),by.y=c("km2_ID")) b$time=i a=b %>%group_by(island) %>%summarize(SSP2_block=sum(WTP *grid_km_censusblock_Pop18_densityKM *365) ) a$time=i all=rbind(b,all) final=rbind(a,final)}df=merge(df,final, all.x =TRUE)colnames(all)[2]="SSP2"all_df=merge(all_df, all, all.x =TRUE)
Predict SSP3
Show code
####This is for SSP3x1 <-readRDS("codedata/x1.rds")x1=merge(SSP3, x1, by.x ="polygon", by.y ="Box_ID_2", all.y =TRUE)x1 <- x1[order(x1$km2_ID,x1$siteID),] ## btw it is correct that the dim(x) is lower than dim(dist) because## I aggregated some siteslength(unique(x1$siteID))### FINISHED LOADING AND MERGING DATASETS ####rm(dist, pop, sitesjoin)### CALCULATE TRAVEL COST ####x1$cost <-0x1$duration[ x1$siteID ==351] <- x1$duration[ x1$siteID ==351] +40## this sites needs 40min walking to be reached## Need to also do this for Hawaii### Change here for different fuel costx1$cost <- x1$distance.meters*0.001* (0.20/1.5 ) ## fuel cost ## assumption on fuel cost:## 20 miles/gallon# $4.3/gallon# means $4.3 per 20 miles --> 0.215 $/mile# 10 km --> 6.2 miles --> $1.33 travel cost per km# 10km * 0.20 / 1.5 = $1.33 so the values coincide with the cost used above.x1$cost <- x1$cost + (x1$duration /60)*3/4*24.4x1$cost <- x1$cost *2## the value for a return trip#### put Molokini cost equal to the one of Makena Landing Beach Park + 100$ (cost of a snorkeling tour)x1$cost[x1$siteID ==388] <- x1$cost[x1$siteID ==359] +100### PREPARE DATA FOR PREDICTIONS ### parametersbeta <- m1$results[,1]X0 <-cbind( x1$cost,x1$home, x1$coastal, x1$citypark, x1$trailall, x1$haleakala, x1$molokini, x1$parking, x1$showers, x1$lifeguard, x1$rock, x1$manmade, x1$beachmedium, x1$beachlarge, x1$surf, x1$swim, x1$snork, x1$res_fish_bio, x1$PNAS, x1$playground, x1$sports, x1$snork*x1$PNAS, x1$snork*x1$res_fish_bio)X0[is.na(X0)] <-0xsim <- x1final <-data.frame(matrix(ncol =2, nrow =0))all <-data.frame(matrix(ncol =2, nrow =0))#colnames(final) <- c("time10", "time20" , "time30" , "time40")#this needs to be ran as a loopfor (i in2:83) { xsim <- x1 xsim$PNAS <- xsim$PNAS *xsim[,i] xsim$PNAS[xsim$PNAS <=0] <-0 X1 <-cbind( xsim$cost,xsim$home, xsim$coastal, xsim$citypark, xsim$trailall, xsim$haleakala, xsim$molokini, xsim$parking, xsim$showers, xsim$lifeguard, xsim$rock, xsim$manmade, xsim$beachmedium, xsim$beachlarge, xsim$surf, xsim$swim, xsim$snork, xsim$res_fish_bio, xsim$PNAS, xsim$playground, xsim$sports, xsim$snork*xsim$PNAS, xsim$snork*xsim$res_fish_bio) X1[is.na(X1)] <-0### CALCULATION OF WTP FOR EACH GRID LOCATION wtpw <-quality.change(beta = beta, ### parametersX0=X0, ### X variables in the baselineX1 = X1, #### X variables in the scenariopid = x1$km2_ID, ### ID of the 1km gridcost =1) ### column of the cost parameter in the X matrix### TOTAL WTP b=merge(wtpw,out, by.x=c("id"),by.y=c("km2_ID")) b$time=i a=b %>%group_by(island) %>%summarize(SSP3_block=sum(WTP *grid_km_censusblock_Pop18_densityKM *365) ) a$time=i all=rbind(b,all) final=rbind(a,final)}df=merge(df,final, all.x =TRUE)colnames(all)[2]="SSP3"all_df=merge(all_df, all, all.x =TRUE)
Data Aggregation
Two datasets were created in the prediction modeling.
Welfare Predictions per KM Grid
Aggregated Totals by population and income weighted by Island Each Year
This code snippet produces a projected summary table of total welfare loss by island, under each scenario (SSP1–SSP3). The results are aggregated over time and space, incorporating:
Annual compensating variation (CV) estimates at the grid level
Population projections for the state of Hawai’i under SSP1–SSP3, used to scale welfare impacts
Two discounting frameworks:
A standard constant discount rate (e.g., circular A-4 rate, typically 3%)
A pluralistic (declining or hyperbolic) discount rate, reflecting alternative time preferences in environmental valuation
These discounted totals provide a long-term estimate of the economic cost of environmental degradation (via coral biomass loss) under different future pathways. The final output summarizes welfare changes per island, scenario, and discounting method, supporting policy evaluation and prioritization.
Show code
df_long <- all_df[c(1:11)] %>%pivot_longer(cols =starts_with("SSP"),names_to ="SSP",values_to ="Value")#points_sf_long$geometry=NULL#points_sf_long$pct_change[is.nan(points_sf_long$pct_change)] <- 0df_long$Year=df_long$time+2018#df_long=merge(df_long, points_sf_long[c(5:7,10)] ,by.x=c("id","Year","SSP"), by.y=c("km2_ID","year","scenario"), all.x=TRUE)library(dplyr)library(zoo)#df_long <- df_long %>% group_by(id, SSP) %>% arrange(year) %>% mutate( pct_change = if_else( SSP != "SSP1", zoo::na.approx(pct_change, x = Year, na.rm = FALSE), pct_change )) %>% ungroup()#df_long$island=droplevels(df_long$island)df_long$island <-as.character(df_long$island)df_long$island[which(df_long$island=="Oahu")]="Oʻahu"df_long$island[which(df_long$island=="Molokai")]="Molokaʻi"df_long$island[which(df_long$island=="Lanai")]="Lānaʻi"df_long$island[which(df_long$island=="Kauai")]="Kauaʻi"df_long$island[which(df_long$island=="Hawaii")]="Hawaiʻi"## Merge Population Of Hawaii Under SSPdf_long=merge(df_long,pop[c(7,8,11)], by.x=c("Year", "SSP"), by.y=c("Year","Scenario"), all.x=TRUE)df_long <- df_long %>%group_by(SSP) %>%arrange(Year, .by_group =TRUE) %>%mutate(Year_j = Year +seq_along(Year)*1e-9) %>%mutate(pop =na.approx(Population_weight, Year_j, na.rm =FALSE)) %>%select(-Year_j) %>%ungroup()# Start Discountingdf_long$NPV_Lane=0df_long$NPV_Lane[which(df_long$Year>2020)]=.03df_long$NPV=0df_long$NPV[which(df_long$Year>2020)]=.02df_long$NPV[which(df_long$Year>2079)]=.019df_long$NPV[which(df_long$Year>2094)]=.018df_long$time_step <- df_long$Year -2020df_long$time_step=df_long$time-2df_long <- df_long %>%mutate( time_step =case_when( time_step %in%1:5~0, time_step >=6~ time_step -5,TRUE~ time_step) )# value into annual terms by population km squaredf_long$pop=as.numeric(df_long$pop)df_long$wtp=df_long$Value*df_long$grid_km_censusblock_Pop18_densityKM*365#df_long$wtp=df_long$Value*df_long$grid_km_censusblock_Pop18_densityKM*365df_long$NPV_WTP=df_long$wtp/(1+df_long$NPV)^df_long$time_step##OMB discounting long term decline df_long$NPV_WTP_Pop=(df_long$wtp*df_long$pop)/(1+df_long$NPV)^df_long$time_stepdf_long$NPV_WTP_Lane=(df_long$wtp*df_long$pop)/(1+df_long$NPV_Lane)^df_long$time_step##pluristic discountingdf_long$NPV_WTP_pluristic=(df_long$wtp*df_long$pop*.4)/(1+0)^df_long$time_step+(df_long$wtp*df_long$pop*.1)/(1)^df_long$time_step+(df_long$wtp*df_long$pop*.3)/(1+.03)^df_long$time_step+(df_long$wtp*df_long$pop*.2)/(1+.1)^df_long$time_stepdf_long$NPV_WTP_pluristic_nonpop=(df_long$wtp*.4)/(1+0)^df_long$time_step+(df_long$wtp*.1)/(1)^df_long$time_step+(df_long$wtp*.3)/(1+.03)^df_long$time_step+(df_long$wtp*.2)/(1+.1)^df_long$time_step#df_long$NPV_WTP_kmgrid=(df_long$wtp*df_long$pct_change)/(1+df_long$NPV)^df_long$time_step
Island Annual Social Welfare
Show code
group.colors <-c(SSP3 ="deeppink", SSP2 ="springgreen", SSP1 ="royalblue")df_island=df_long %>%group_by(island, SSP, Year) %>%summarise(NPV_WTP_Pop=sum(NPV_WTP_Pop)/1000, NPV_WTP_pluristic=sum(NPV_WTP_pluristic)/1000)ggplot(df_island, aes(x = Year)) +geom_line(aes(y = NPV_WTP_Pop, color = SSP, group = SSP)) +geom_line(aes(y = NPV_WTP_pluristic, color = SSP, group = SSP)) +geom_ribbon(aes(ymin = NPV_WTP_pluristic, ymax = NPV_WTP_Pop, fill = SSP, group = SSP),alpha =0.3, linetype =0 ) +scale_color_manual(values = group.colors) +scale_fill_manual(values = group.colors) +theme_minimal() +theme(text =element_text(family ="Times New Roman"),plot.title =element_text(hjust =0.5),legend.position ="bottom",legend.background =element_rect(fill ="white") ) +xlab("Year") +ylab("Thousands Dollars") +ggtitle("Annual Social Welfare Impacts (in Thousands Dollars)") +facet_wrap(~factor(island, levels =c("Lānaʻi", "Molokaʻi", "Kauaʻi", "Hawaiʻi", "Maui", "Oʻahu")),ncol =2, scales ="free")ggsave('images/islandgraphpluristic_new.png', dpi =300, height =8, width =8, unit ='in')
Tables
Show code
# Adjust for inflation from original data 2017 to 2014library(knitr)t=df_long %>%group_by(SSP) %>%summarise(NPV_WTP=sum(NPV_WTP)/1000000000*1.249,NPV_WTP_Pop=sum(NPV_WTP_Pop)/1000000000*1.249, NPV_WTP_pluristic_nonpop=sum(NPV_WTP_pluristic_nonpop)/1000000000*1.249,NPV_WTP_pluristic=sum(NPV_WTP_pluristic)/1000000000*1.249)kable(t, caption ="Summary of NPV_WTP_pluristic_nonpop", digits =2)
Grid Island
The raw welfare estimates generated in previous steps are not yet adjusted for differences in income levels or population density. The next code snippet computes total willingness to pay (WTP) by:
Aggregating individual welfare estimates by income tract and grid cell
Weighting by local population to reflect the total affected individuals
This adjusted dataset is especially useful for understanding distributional impacts of environmental change and for producing spatially explicit visualizations of welfare loss.
In the paper we present 2030, 2050, 2100 but here we have also 2075
Show code
# Define the cutpoints for 7 intervalshawaii_counties=st_read("codedata/Coastline.shp")hawaii_counties <- sf::st_transform(hawaii_counties, 4326)all_df <-readRDS("codedata/all_grids.rds")locations=x1[c(87,90,91)]locations=unique(locations)all_df=merge(all_df, locations, by.x=c("id"),by.y=c("km2_ID"))all_df <- all_df %>%mutate(SSP1_WTP_bin =case_when( SSP1_TotalWTP <=-1e6~"≤ -1M", SSP1_TotalWTP <=-1e5~"-1M to -100K", SSP1_TotalWTP <=-1e3~"-100K to -1K", SSP1_TotalWTP <=-100~"-1K to -100", SSP1_TotalWTP <0~"-100 to 0", SSP1_TotalWTP ==0~"0", SSP1_TotalWTP <=100~"0 to 100", SSP1_TotalWTP <=1e3~"100 to 1K", SSP1_TotalWTP <=1e4~"1K to 10K",TRUE~"> 10K" ))all_df <- all_df %>%mutate(SSP2_WTP_bin =case_when( SSP2_TotalWTP <=-1e6~"≤ -1M", SSP2_TotalWTP <=-1e5~"-1M to -100K", SSP2_TotalWTP <=-1e3~"-100K to -1K", SSP2_TotalWTP <=-100~"-1K to -100", SSP2_TotalWTP <0~"-100 to 0", SSP2_TotalWTP ==0~"0", SSP2_TotalWTP <=100~"0 to 100", SSP2_TotalWTP <=1e3~"100 to 1K", SSP2_TotalWTP <=1e4~"1K to 10K",TRUE~"> 10K" ))all_df <- all_df %>%mutate(SSP3_WTP_bin =case_when( SSP3_TotalWTP <=-1e6~"≤ -1M", SSP3_TotalWTP <=-1e5~"-1M to -100K", SSP3_TotalWTP <=-1e3~"-100K to -1K", SSP3_TotalWTP <=-100~"-1K to -100", SSP3_TotalWTP <0~"-100 to 0", SSP3_TotalWTP ==0~"0", SSP3_TotalWTP <=100~"0 to 100", SSP3_TotalWTP <=1e3~"100 to 1K", SSP3_TotalWTP <=1e4~"1K to 10K",TRUE~"> 10K" ))color_palette <-c("≤ -1M"="darkred","-1M to -100K"="brown","-100K to -1K"="lightcoral","-1K to -100"="pink","-100 to 0"="mistyrose","0"="white","0 to 100"="greenyellow","100 to 1K"="limegreen","> 10K"="darkgreen")all_df$SSP1_WTP_bin <-factor( all_df$SSP1_WTP_bin,levels =names(color_palette))all_df$SSP2_WTP_bin <-factor( all_df$SSP2_WTP_bin,levels =names(color_palette))all_df$SSP2_WTP_bin <-factor( all_df$SSP2_WTP_bin,levels =names(color_palette))# Then plot:ggplot(all_df %>%filter(Year %in%c(2020, 2050, 2075, 2100)),aes(x = longitude, y = latitude, color = SSP1_WTP_bin)) +geom_point(size =0.5, alpha =1) +geom_sf(data = hawaii_counties,fill =NA,color ="black",size =0.4,inherit.aes =FALSE ) +coord_sf(xlim =c(-161, -154), ylim =c(18.5, 22.5)) +scale_color_manual(values = color_palette,name ="Total WTP",drop =FALSE,limits =names(color_palette) ) +facet_wrap(vars(Year), ncol =2) +theme_light()
Animation Welfare
These produce animations of changes in annual welfare to the year 2100
The code chunk runs the animation and saves the file.
The Markdown line right after brings the GIF into the rendered output.
Make sure the GIF file path is correct relative to the document, or specify the path if needed.
Legend for the following animations
Show code
color_palette <-c("≤ -1M"="darkred","-1M to -100K"="brown","-100K to -1K"="lightcoral","-1K to -100"="pink","-100 to 0"="mistyrose","0"="white","0 to 100"="greenyellow","100 to 1K"="limegreen","> 10K"="darkgreen")# Create a blank plot canvasplot(NULL, xaxt ="n", yaxt ="n", bty ="n",xlab ="", ylab ="", xlim =c(0, 1), ylim =c(0, 1))# Draw the standalone legendlegend("center",legend =names(color_palette),fill =unname(color_palette),bty ="o", # border around legendcex =1.0, # text sizetitle ="Total WTP",title.cex =1.2, # title sizencol =1,xpd =TRUE)