diff --git a/howTo/openGeogAPI/app3.R b/howTo/openGeogAPI/app3.R new file mode 100644 index 0000000000000000000000000000000000000000..3d62114e14dea2ce58516720ba20b9c5bd27a975 --- /dev/null +++ b/howTo/openGeogAPI/app3.R @@ -0,0 +1,289 @@ +# Load libraries ---- + +library(readxl) +library(ggplot2) +library(sf) +library(htmltools) +library(leaflet) +library(plotly) +library(dplyr) +library(reshape2) +library(RColorBrewer) + +# Construct colour palette ---- +industry_pal <- brewer.pal(n = 8, name = "Greys")[4:8] # industry greys, 5 categories +domestic_pal <- brewer.pal(n = 4, name = "Blues")[2:4] # domestic blues, 3 categories +transport_pal <- brewer.pal(n = 6, name = "Oranges")[2:6] # transport oranges, 5 categories +lulucf_pal <- brewer.pal(n = 9, name = "Greens")[4:9] # lulucf greens, 6 categories + +# for details +detailed_pal <- c(industry_pal, domestic_pal, transport_pal, lulucf_pal) + +# for totals/outlines +totals_pal <- c(brewer.pal(n = 9, name = "Greys")[8], + brewer.pal(n = 9, name = "Blues")[8], + brewer.pal(n = 9, name = "Oranges")[8], + brewer.pal(n = 9, name = "Greens")[7:8]) + +# List local authority areas to load +# These used to filter emissions data +# and construct Open Geog API query (geo_query ... to do) +las_to_load <- c("Southampton","Portsmouth","Winchester", + "Eastleigh","Isle of Wight","Fareham", + "Gosport","Test Valley","East Hampshire", + "Havant","New Forest","Hart","Basingstoke and Deane") + +# Load GHG emissions data ---- + +url_to_get <- "https://assets.publishing.service.gov.uk/government/uploads/system/uploads/attachment_data/file/894787/2005-18-uk-local-regional-co2-emissions.xlsx" + +tempf <- tempfile(fileext = ".xlsx") +download.file(url_to_get, tempf, method = "curl") + +dt <- readxl::read_xlsx(tempf, sheet = "Full dataset",skip = 1) + +x_min <- min(dt$Year) +x_max <- max(dt$Year) + +# Load LA geography ---- + +# URL as API query - sometimes we don't want all boundaries +geo_query <- "https://ons-inspire.esriuk.com/arcgis/rest/services/Administrative_Boundaries/Local_Authority_Districts_December_2018_Boundaries_UK_BGC/MapServer/0/query?where=lad18nm%20IN%20(%27Southampton%27,%27Portsmouth%27,%27Winchester%27,%27Eastleigh%27,%27Isle%20of%20Wight%27,%27Fareham%27,%27Gosport%27,%27Test%20Valley%27,%27East%20Hampshire%27,%27Havant%27,%27New%20Forest%27,%27Hart%27,%27Basingstoke%20and%20Deane%27)&outFields=lad18cd,lad18nm,long,lat&outSR=4326&f=geojson" + +message("Loading LA geometry from ONS Open Geography API") +sf_data <- st_read(geo_query) +#plot(st_geometry(sf_data)) + +# Useful lookup spatial reference for CRS +# https://spatialreference.org/ref/epsg/27700/ +st_coord_sys <- st_crs(sf_data) # check coord system +st_coord_sys # current coord system EPSG: 4326 (is what leaflet wants - good) + +# transform the coord system if required +if(st_coord_sys$epsg != 4326){ + sf_data <- st_transform(sf_data, "+proj=longlat +datum=WGS84") +} + +# Process data ---- +# Filter local authorities and correct population +per_capita_dt <- dt %>% + filter(Name %in% las_to_load) %>% + rename(Population = `Population ('000s, mid-year estimate)`) %>% + mutate(Population = Population*1000) + +# Add Hampshire totals (sum of all las in las_to_load) to calculate averages across las +total_hampshire_dt <- dt %>% + filter(Name %in% las_to_load) %>% + rename(Population = `Population ('000s, mid-year estimate)`) %>% + mutate(Population = Population*1000) %>% + group_by(Year) %>% + summarise_if(is.numeric, sum, na.rm = TRUE) %>% + mutate(Name = " Hampshire", + `CTRY18NM/RGN18NM` = "South East", + `Second Tier Authority` = "Hampshire", + Code = "E00000000") %>% + select(`CTRY18NM/RGN18NM`,`Second Tier Authority`,Name,Code,Year,everything()) + +per_capita_dt <- rbind(per_capita_dt,total_hampshire_dt) + +per_cap_fun <- function(x) x*1000/per_capita_dt$Population +per_capita_totals <- data.frame(per_capita_dt[c(1:5,30)], lapply(per_capita_dt[c(11,15,21,28,29,32,33)], per_cap_fun) ) +per_capita_detail <- data.frame(per_capita_dt[c(1:5,30)], lapply(per_capita_dt[c(6:10,12:14,16:20,22:27,29,32,33)], per_cap_fun) ) +# Note that for hampshire LAs there are no emissions in categories Q or S + +# Create plot tables ---- + +pc_detail_plot <- data.frame(per_capita_detail[c(1:5,7:25)]) +pc_detail_plot <- melt(pc_detail_plot, id.vars = c("CTRY18NM.RGN18NM","Second.Tier.Authority","Name","Code","Year")) + +pc_general_plot <- data.frame(per_capita_totals[c(3,5,11:13)]) + +# Calculate emissions and removals for LULUCF separately +per_capita_lulucf <- pc_detail_plot %>% + filter(grepl("LULUCF", variable)) %>% + group_by(Name,Year) %>% + summarise( + LULUCF.emissions = sum(value[value > 0]), + LULUCF.removals = sum(value[value < 0])) + +per_capita_totals <- left_join(per_capita_totals,per_capita_lulucf, by = c("Name","Year")) + +pc_totals_plot <- data.frame(per_capita_totals[c(1:5,7:9,14,15)]) +pc_totals_plot <- melt(pc_totals_plot, id.vars = c("CTRY18NM.RGN18NM","Second.Tier.Authority","Name","Code","Year")) + + + +# Functions ---- + +ghg_subset <- function(dt, auth_area = " Hampshire"){ + dt <- dt %>% + filter(dt$Name %in% auth_area) + # add filter for categories with input$ +} + + + +ghg_subset2 <- function(dt, auth_area = " Hampshire", plot_year = 2018){ + dt <- dt %>% + filter(dt$Name %in% auth_area, + dt$Year == plot_year) + # add filter for categories with input$ +} + +# to expand y axis +expand_ggplot <- function(plot) { + y_min <- floor(min(layer_data(plot)$y, na.rm=TRUE)) + y_max <- ceiling(sum(layer_data(plot)$y, na.rm=TRUE)) + coord_flip(ylim=c(y_min, y_max)) + scale_y_continuous(breaks = y_min:y_max) +} + +# Create map (leaflet) ---- + +# create popup first (requires htmltools) +library(htmltools) +sf_data$popup_text <- + paste("Locial authority area code: ","<b>", sf_data$lad18cd, "</b>", + '<br/>', 'Local authority: ', '<b>', sf_data$lad18nm, '</b>', ' ') %>% + lapply(htmltools::HTML) + +# App layout ---- + +ui <- fluidPage( + + + titlePanel("Hampshire local authority ghg emission visualisation"), + + fluidRow( + + column(5, + wellPanel("Click map to select local authority"), + leafletOutput("authmap",height = "600px")), + + column(7, + wellPanel("Use slider to select year to view in panel below and mouse-over to view more detail"), + sliderInput("yearSlider", label = "Year", min = 2005, + max = 2018, value = 2018, step = 1, round = TRUE, + ticks = FALSE, width = "90%", sep = ""), + plotOutput("plot", height = "400px"), + plotOutput("bar", height = "150px")) + ), + + fluidRow( + column(5), + column(7) + + ) + +) + + + # *Input() functions + # *Output() functions + + + +server <- function(input, output, session) { + + output$authmap <- renderLeaflet({ + + leaflet() %>% + addTiles() %>% # Add default OpenStreetMap map tiles + addPolygons(data = sf_data, layerId = ~(lad18nm), + color = "blue", fillColor = "blue", fillOpacity = 0.2, weight = 1.5, + #popup = ~(lad18nm), # popups clicked + label = ~(popup_text), # define labels + labelOptions = labelOptions( # label options + style = list("font-weight" = "normal", padding = "2px 2px"), + direction = "auto"), + highlight = highlightOptions( + weight = 5, + color = "#666", + fillOpacity = 0.7, + bringToFront = TRUE)) + + }) + + observeEvent( + + input$authmap_shape_click, { + + click <- input$authmap_shape_click + + print(click$id) + + output$selected_auth <- renderText({ + print(paste0("Local authority area selected: ",click$id)) + }) + + } + ) + + + output$plot <- renderPlot({ + + plotCaption = paste0("Emissions data: Department for Business, Energy & Industrial Strategy", + "\nLocal authority boundary data (2018): ONS Open Geography Portal", + "\nVisualisation: rushby.shinyapps.io/LAemissions") + + if(is.null(input$authmap_shape_click$id)){ + auth_area <- " Hampshire" + } else { + auth_area <- input$authmap_shape_click$id + } + + plotTitle = paste0("Greenhouse gas emissions by sector for ",auth_area, " - ",x_min, " to ",x_max) + + ggplot() + + geom_col(ghg_subset(dt = pc_detail_plot, auth_area = auth_area), mapping = aes(x = Year, y = value, fill = variable), position = "stack") + + geom_col(ghg_subset(dt = pc_totals_plot, auth_area = auth_area), mapping = aes(x = Year, y = value, colour = variable), fill = "none", position = "stack") + + geom_hline(yintercept=0, lwd=0.4, colour="black", linetype = "dashed") + + coord_cartesian(ylim = c(-1,15)) + + scale_y_continuous(labels=abs) + + scale_x_continuous(breaks = 2005:2018) + + scale_color_manual(values = totals_pal, guide = FALSE) + + scale_fill_manual(values = detailed_pal) + + labs(x = "Year", + y = "Emissions per capita, tCO2", + fill = "Source", + title = plotTitle, + caption = plotCaption) + + theme(legend.position = "right") + + theme_classic() + + }) + + output$bar <- renderPlot({ + + if(is.null(input$authmap_shape_click$id)){ + auth_area <- " Hampshire" + } else { + auth_area <- input$authmap_shape_click$id + } + + plotTitle = paste0("Greenhouse gas emissions by sector for ",auth_area, " - ",input$yearSlider) + + plot <- ggplot() + + geom_col(data = ghg_subset2(dt = pc_detail_plot, auth_area = auth_area, plot_year = input$yearSlider), + mapping = aes(x = Name, y = value, fill = variable), position = "stack") + + geom_hline(yintercept=0, lwd=0.4, colour="black", linetype = "dashed") + + coord_flip() + + scale_color_manual(values = totals_pal) + + scale_fill_manual(values = detailed_pal) + + theme_minimal() + + labs(y = "Emissions per capita (tonnes of carbon dioxide/person)", + title = plotTitle) + + theme(axis.text.y = element_blank(), + axis.title.y = element_blank(), + axis.ticks.y = element_blank(), + #axis.title.x = element_blank(), + panel.grid.major.y = element_blank(), + legend.position = "none") + + plot + expand_ggplot(plot) + + }) +} + + +shinyApp(ui = ui, server = server) \ No newline at end of file