Catchment Households and Deprivation, Brighton and Hove
In the map below, every circle represents a postcode in Brighton and Hove, sized according to the estimated number of households with dependent children living in that postcode, and coloured according to the proportion of all children in that postcode aged 0-15, living in income deprived families.
Hover the mouse over each dot to see the postcode and estimated counts of households with dependent children.
The boundaries on the map represent the current (2024/25) school catchment boundaries (blue) and the proposed 2026/27 boundaries (red) taken from the Catchment Area Postcode List published by Brighton and Hove District Council
The graphs below the map
These estimates use postcode level population and household estimates derived from the 2021 Census, obtained from NOMIS - https://www.nomisweb.co.uk/sources/census_2021_pc
Details of households with dependent children taken from the 2021 Census - Table TS003 Household Composition - https://www.nomisweb.co.uk/sources/census_2021_bulk
Deprivation data is taken from the 2019 Index of Multiple Deprivation - https://imd-by-geo.opendatacommunities.org - In this case I have used the Income Deprivation Affecting Children Index - IDACI.
Counts of households with dependent children have been estimated using household proportions at postcode level to distribute output area level numbers of households with dependent children proportionally to each postcode in each output area.
Code
library(sf) # For spatial data manipulation
library(dplyr) # For data manipulation
library(ggplot2) # For plotting
library(RColorBrewer) # For color palettes
# 1. Perform spatial join (use your existing data)
<- st_join(bn_postcodes_pop1, optionZ, join = st_within)
joined_data_city
# 2. Aggregate the data for the entire city
<- joined_data_city %>%
aggregated_data_city group_by(idaci_decile) %>%
summarise(total_dep_ch = sum(pcd_dep_ch_hh_count_round, na.rm = TRUE)) %>%
ungroup()
# 3. Create a bar graph for the entire city
ggplot(aggregated_data_city, aes(x = factor(idaci_decile), y = total_dep_ch, fill = idaci_decile)) +
geom_bar(stat = "identity") +
scale_fill_gradientn(
colors = brewer.pal(11, "RdYlBu"),
limits = c(0, 10), # Ensure 0 maps to red and 10 maps to blue
breaks = 0:10, # Optional: discrete legend ticks for each decile
name = "IDACI Decile"
+
) labs(
title = "Count of Households with Dependent Children by IDACI Decile - Brighton and Hove",
x = "IDACI Decile",
y = "Count of Households with Dependent Children"
+
) theme_minimal() +
theme(legend.position = "bottom") # Adjust the legend position
Rayshader Plot
Code
# library(basemaps)
#
# # Define bounding box for your map area
# # Calculate bounding box explicitly
# bbox <- st_bbox(bn_postcodes_pop1, crs = 4326)
#
# # set defaults for the basemap
# set_defaults(ext = bbox, map_service = "esri", map_type = "world_light_gray_base")
#
# # Overlay with your height plot or main plot
# osm_basemap <- ggplot() +
# basemap_gglayer(ext = bbox) + # Pass bbox explicitly here
# scale_fill_identity() +
# coord_sf()
#
#
# osm_basemap
#
# # Render the rayshader plot with the basemap
# osm_basemap %>%
# plot_gg(
# ggobj_height = height_plot,
# multicore = TRUE,
# width = 5,
# height = 5,
# scale = 50, # Reduce height scaling
# windowsize = c(800, 800),
# shadow_intensity = 0.5 # Optional: adjust shadow for realism
# )
Code
<- ggplot(rayshader_data, aes(x = x, y = y, colour = z)) +
height_plot geom_point(size = 0.05) + # Raster fills for continuous height mapping
scale_colour_gradientn(
colors = brewer.pal(9, "YlGnBu"), # Adjust as needed
limits = c(min(rayshader_data$z, na.rm = TRUE), max(rayshader_data$z, na.rm = TRUE)),
name = "Height"
+
) theme_minimal(base_size = 10) +
labs(
title = "Households with Dependent Children",
colour = "IDACI Decile"
+
) theme(
panel.background = element_rect(fill = "white", color = NA), # White background
plot.background = element_rect(fill = "white", color = NA), # White plot background
legend.background = element_rect(fill = "white", color = NA),
legend.position = "none" # Disable all legends# White legend background
# Minimal theme for height mapping
)
#height_plot
<- ggplot(rayshader_data, aes(x = x, y = y, colour = w)) +
main_plot geom_point(size = 0.05) +
scale_colour_gradientn(
colors = brewer.pal(11, "RdYlBu"),
limits = c(0, 10),
name = "IDACI Decile"
+
) theme_minimal(base_size = 10) +
labs(
title = "IDACI Decile",
colour = "IDACI Decile"
+
) theme(
panel.background = element_rect(fill = "white", color = NA), # White background
plot.background = element_rect(fill = "white", color = NA), # White plot background
legend.background = element_rect(fill = "white", color = NA),
legend.position = "none" # Disable all legends# White legend background
)
#main_plot
%>%
main_plot plot_gg(
ggobj_height = height_plot, # Specify height mapping plot
multicore = TRUE,
width = 5,
height = 5,
scale = 50, # Adjust scale for height exaggeration
windowsize = c(1200, 1200),
sunangle=225
)
# Add 3D rendering
render_camera(theta = 10, phi = 30, zoom = 0.4)
::rglwidget() rgl