-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathapp.R
257 lines (212 loc) · 9.13 KB
/
app.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# Conveyal Post-Processing Tool
# Henry.McKay@dot.ca.gov
# Last update: 04/18/2023
# Load packages (will need to be installed first if not already)
library(shiny)
library(shinyWidgets)
library(raster)
library(rgdal)
library(dplyr)
library(DT)
library(data.table)
library(leaflet)
library(leaflet.extras)
library(sf)
library(stats)
library(terra)
### User interface ###
# Tab 1 UI: Parameters
tab1 <- tabPanel(
title = "Project Analysis",
sidebarLayout(
sidebarPanel(
textInput("project_name", "Project Name", value = "", width = NULL, placeholder = NULL),
helpText("Upload Conveyal Outputs"),
fileInput("baseline_tiff", "Baseline Conveyal .TIFF Output", multiple = FALSE),
fileInput("project_tiff", "Project Conveyal .TIFF Output", multiple = FALSE),
fileInput("weight_tiff", "Weight .TIFF", multiple = FALSE),
fileInput("shapefile_input", "Project Extent Shapefile", multiple = T,
accept = c('.shp','.dbf','.sbn','.sbx','.shx','.prj', '.cpg')),
numericInput("buffer", "Analysis Area Buffer (kilometers)", 3),
download1 <- downloadButton('download1', "Export CSV")
),
mainPanel(
table1 <- dataTableOutput("table1")
)
)
)
# Tab 2 UI: Parameters
tab3 <- tabPanel(
title = "Map",
sidebarLayout(
sidebarPanel(
selectInput("map_options", "Select Raster to Map", choices = c("Baseline Accessibility",
"Project Accessibility",
"Accessibility Change",
"Weighted Accessibility Change")),
helpText("Note: The weighted accessibility change map is meant only to show where the relative
changes in accessibility occur when accounting for a weighitng factor, using a color scale.
Individual numbers associated with these changes should only be analyzed in the context
of aggregate metrics, such as the ones shown on the project analysis tab.")
),
mainPanel(
tags$style(type = "text/css", "#map1 {height: calc(100vh - 100px) !important; }"),
leafletOutput("map1")
)
)
)
# Assemble UI
ui <- navbarPage(
title = "Conveyal Post-Processing Tool",
tab1,
tab3
)
### END User Interface ###
### Server ###
server <- function(input, output, session) {
options(shiny.maxRequestSize=30*1024^2)
# Shapefile upload (if the input was a GEOJSON, KML, etc, this would be one line of code)
project_extent <- reactive({
project_input <- input$shapefile_input
tempdirname <- dirname(project_input$datapath[1])
# Rename files
for (i in 1:nrow(project_input)) {
file.rename(
project_input$datapath[i],
paste0(tempdirname, "/", project_input$name[i])
)
}
# Read shapefile from upload
project_extent <- readOGR(paste(tempdirname,
project_input$name[grep(pattern = "*.shp$", project_input$name)],
sep = "/"
))
project_extent <- st_as_sf(project_extent)
project_extent <- st_transform(project_extent, crs = 4326)
})
# Calculate accessibility metrics
eval_table <- reactive({
# Validate input .tiff files
validate(
need(input$baseline_tiff != "", "Please upload baseline .tiff file"),
need(input$project_tiff != "", "Please upload a project .tiff file"),
need(input$weight_tiff != "", "Please upload a weight .tiff file"),
need(input$shapefile_input != "", "Please upload a project shapefile")
)
# Read in project shapefile and apply buffer at specified distance
project_extent <- st_as_sf(project_extent())
project_extent <- st_transform(project_extent, crs = 3857)
buffer <- st_buffer(project_extent, (input$buffer * 1000)) # Convert input (in kilometers) to meters
buffer_diss <- st_as_sf(st_union(buffer))
# Read in baseline and build .TIFF files
baseline <- raster(input$baseline_tiff$datapath)
build <- raster(input$project_tiff$datapath)
baseline <- crop(baseline, build)
### Calculate metrics
# Read weight raster, crop to buffer
weight <- raster(input$weight_tiff$datapath)
weight <- crop(weight, build)
weight_cropped <- mask(weight, buffer_diss)
# Baseline
baseline_cropped <- mask(baseline, buffer_diss)
baseline_num <- sum(values(baseline_cropped), na.rm = T)
# Build
build_cropped <- mask(build, buffer_diss)
build_num <- sum(values(build_cropped), na.rm = T)
# Difference
difference <- build_cropped - baseline_cropped
# Weight baseline and build .TIFFs
baseline_weighted <- baseline * weight_cropped
build_weighted <- build * weight_cropped
# Weighted Baseline
w_baseline_cropped <- mask(baseline_weighted, buffer_diss)
w_baseline_num <- sum(values(w_baseline_cropped), na.rm = T)
# Weighted Build
w_build_cropped <- mask(build_weighted, buffer_diss)
w_build_num <- sum(values(w_build_cropped), na.rm = T)
# Compute weighted % change in accessibility
weighted_diff_pct <- ((w_build_num - w_baseline_num) / w_baseline_num)
###
# Compute average change in accessibility
weighted_access_change <- weighted.mean(values(difference), values(weight_cropped), na.rm = T)
# Compute % change in accessibility
diff_pct <- ((build_num - baseline_num) / baseline_num)
# Compute average change in accessibility
avg_diff <- mean((values(build_cropped) - values(baseline_cropped)), na.rm = T)
# Create summary data frame
project <- input$project_name
pct_change_access <- diff_pct
pct_change_access_weighted <- weighted_diff_pct
avg_change_access <- avg_diff
weighted_avg_change_access <- weighted_access_change
eval_table <- data.frame(project,
pct_change_access,
pct_change_access_weighted,
avg_change_access,
weighted_avg_change_access)
})
# Render/format data table
output$table1 = renderDataTable({
datatable(eval_table()) %>%
formatPercentage(c("pct_change_access"), 2) %>%
formatPercentage(c("pct_change_access_weighted"), 2) %>%
formatCurrency(c("avg_change_access"), currency = "", interval = 3, mark = ",", digits = 4) %>%
formatCurrency(c("weighted_avg_change_access"), currency = "", interval = 3, mark = ",", digits = 4)
})
# Download summary table as csv
output$download1 <- downloadHandler(
filename = function() {
"Accessibility_Project_Evaluation.csv"
},
content = function(file) {
write.csv(eval_table(),
file,
row.names=FALSE)
}
)
# Render project map
output$map1 <- renderLeaflet({
# Validate input .tiff files
validate(
need(input$baseline_tiff != "", "Please upload a baseline .tiff file"),
need(input$project_tiff != "", "Please upload a project .tiff file"),
need(input$weight_tiff != "", "Please upload a weight .tiff file"),
need(input$shapefile_input != "", "Please upload a project shapefile")
)
baseline <- raster(input$baseline_tiff$datapath)
build <- raster(input$project_tiff$datapath)
project_extent <- st_as_sf(project_extent())
project_extent <- st_transform(project_extent, crs = 3857)
buffer <- st_buffer(project_extent, (input$buffer * 1000))
buffer_diss <- st_as_sf(st_union(buffer))
# Read in baseline and build .TIFF files
baseline_clipped <- mask(baseline, buffer_diss)
build_clipped <- mask(build, buffer_diss)
# Compute change in accessibility
difference_clipped <- mask((build - baseline), buffer_diss)
# Weighting
clipped_weight <- mask(raster(input$weight_tiff$datapath), buffer_diss)
weighted_differences_clipped <- (build_clipped * clipped_weight) - (baseline_clipped * clipped_weight)
if(input$map_options == "Baseline Accessibility") {
raster_file <- baseline_clipped
} else if(input$map_options == "Project Accessibility") {
raster_file <- build_clipped
} else if(input$map_options == "Accessibility Change") {
raster_file <- difference_clipped
} else if(input$map_options == "Weighted Accessibility Change") {
raster_file <- weighted_differences_clipped
}
# Define color pallette
pal <- colorNumeric(c("viridis"), values(raster_file), na.color = "transparent")
# Render leaflet map
leaflet() %>%
addProviderTiles(providers$CartoDB.Positron) %>%
addRasterImage(raster_file, colors = pal, opacity = .6, project = F) %>%
addPolylines(data = project_extent()) %>%
addLegend(pal = pal, values = values(raster_file), title = input$map_options) %>%
addFullscreenControl()
})
}
### END Server ###
# Run app
shinyApp(ui, server)