Skip to content

Commit

Permalink
Add an IMD layer
Browse files Browse the repository at this point in the history
  • Loading branch information
dabreegster committed Aug 14, 2023
1 parent eb97f37 commit 87b3323
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 18 deletions.
26 changes: 10 additions & 16 deletions src/lib/browse/CensusOutputAreaLayerControl.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import type { MapGeoJSONFeature } from "maplibre-gl";
import {
hoveredToggle,
makeColorRamp,
overwriteLineLayer,
overwritePmtilesSource,
overwritePolygonLayer,
Expand Down Expand Up @@ -32,7 +33,11 @@
colorBy = "";
}
if (colorBy) {
$map.setPaintProperty(name, "fill-color", makeColorRamp());
$map.setPaintProperty(
name,
"fill-color",
makeColorRamp(["get", colorBy], makeLimits(), colorScale)
);
// InteractiveLayer manages the polygon layer, but we also need to control the outline
$map.setLayoutProperty(outlineLayer, "visibility", "visible");
} else {
Expand Down Expand Up @@ -105,20 +110,6 @@
return [0, 4700, 13000, 33000, 94000, 1980000];
}
}
function makeColorRamp(): any[] {
let limits = makeLimits();
let fillColor: any[] = ["step", ["get", colorBy]];
for (let i = 1; i < limits.length; i++) {
fillColor.push(colorScale[i - 1]);
fillColor.push(limits[i]);
}
// Repeat the last color. The upper limit is exclusive, meaning a value
// exactly equal to it will use this fallback. For things like percentages,
// we want to set 100 as the cap.
fillColor.push(colorScale[colorScale.length - 1]);
return fillColor;
}
</script>

<Checkbox
Expand Down Expand Up @@ -234,7 +225,10 @@
</Checkbox>
{#if colorBy == "population_density"}
<p>(people per square kilometres)</p>
<SequentialLegend {colorScale} limits={makeLimits()} />
<SequentialLegend
{colorScale}
limits={makeLimits().map((x) => x.toLocaleString())}
/>
{/if}

<InteractiveLayer
Expand Down
96 changes: 96 additions & 0 deletions src/lib/browse/ImdLayerControl.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<script lang="ts">
import type { MapGeoJSONFeature } from "maplibre-gl";
import {
hoveredToggle,
makeColorRamp,
overwriteLineLayer,
overwritePmtilesSource,
overwritePolygonLayer,
} from "../../maplibre_helpers";
import { map } from "../../stores";
import { ExternalLink, HelpButton, InteractiveLayer } from "../common";
import { Checkbox } from "../govuk";
import { colors } from "./colors";
import SequentialLegend from "./SequentialLegend.svelte";
let name = "imd";
let outlineLayer = `${name}-outline`;
let colorScale = colors.sequential_low_to_high;
// The deciles are [1, 10]. The 5 colors cover two each.
let limits = [0, 2, 4, 6, 8, 10];
overwritePmtilesSource(
$map,
name,
`https://atip.uk/layers/v1/${name}.pmtiles`
);
overwritePolygonLayer($map, {
id: name,
source: name,
sourceLayer: name,
// Decile 1 is the most deprived, but we want to invert for the color scale
color: makeColorRamp(["-", 10, ["get", "decile"]], limits, colorScale),
opacity: hoveredToggle(0.5, 0.7),
});
overwriteLineLayer($map, {
id: outlineLayer,
source: name,
sourceLayer: name,
color: "black",
width: 0.5,
});
let show = false;
// InteractiveLayer manages the polygon layer, but we also need to control the outline
$: {
if ($map.getLayer(outlineLayer)) {
$map.setLayoutProperty(
outlineLayer,
"visibility",
show ? "visible" : "none"
);
}
}
function tooltip(feature: MapGeoJSONFeature): string {
return (
`<p>${feature.properties.LSOA11CD} has an IMD score of <b>${feature.properties.score}</b></p>` +
`<p>Rank: <b>${feature.properties.rank.toLocaleString()}</b> / 32,844 LSOAs</p>`
);
}
</script>

<Checkbox id={name} bind:checked={show}>
Indices of Multiple Deprivation
<span slot="right">
<HelpButton>
<p>
The 2019 English IMD scores come from <ExternalLink
href="https://data-communities.opendata.arcgis.com/datasets/communities::indices-of-multiple-deprivation-imd-2019-1/explore"
>
DLUCH GIS
</ExternalLink>. Note the LSOAs identified are from the 2011 census. A
detailed breakdown of the score across different categories can be found <ExternalLink
href="http://dclgapps.communities.gov.uk/imd/iod_index.html"
>
here
</ExternalLink>.
</p>
<p>
License: <ExternalLink
href="http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/"
>
Open Government License
</ExternalLink>. Contains OS data &copy; Crown copyright and database
right 2023.
</p>
</HelpButton>
</span>
</Checkbox>
{#if show}
<SequentialLegend {colorScale} limits={["Least deprived", "Most deprived"]} />
{/if}

<InteractiveLayer layer={name} {tooltip} {show} clickable={false} />
4 changes: 2 additions & 2 deletions src/lib/browse/SequentialLegend.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
export let colorScale: string[];
export let limits: number[];
export let limits: any[];
</script>

<div style="display: flex">
Expand All @@ -12,6 +12,6 @@
</div>
<div style="display: flex; justify-content: space-between;">
{#each limits as limit}
<span>{limit.toLocaleString()}</span>
<span>{limit}</span>
{/each}
</div>
20 changes: 20 additions & 0 deletions src/maplibre_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,24 @@ export function hoveredToggle<Type>(
] as DataDrivenPropertyValueSpecification<Type>;
}

// Helper for https://maplibre.org/maplibre-style-spec/expressions/#step.
export function makeColorRamp(
input: DataDrivenPropertyValueSpecification<number>,
limits: number[],
colorScale: string[]
): DataDrivenPropertyValueSpecification<string> {
let step: any[] = ["step", input];
for (let i = 1; i < limits.length; i++) {
step.push(colorScale[i - 1]);
step.push(limits[i]);
}
// Repeat the last color. The upper limit is exclusive, meaning a value
// exactly equal to it will use this fallback. For things like percentages,
// we want to set 100 as the cap.
step.push(colorScale[colorScale.length - 1]);
return step as DataDrivenPropertyValueSpecification<string>;
}

// Suitable for passing to map.fitBounds. Work around https://github.com/Turfjs/turf/issues/1807.
export function bbox(gj: GeoJSON): [number, number, number, number] {
return turfBbox(gj) as [number, number, number, number];
Expand Down Expand Up @@ -291,6 +309,8 @@ const layerZorder = [
"local_planning_authorities-outline",
"census_output_areas",
"census_output_areas-outline",
"imd",
"imd-outline",
// Then smaller optional layers on top
"schools",
"hospitals",
Expand Down
2 changes: 2 additions & 0 deletions src/pages/BrowseSchemes.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import { processInput, type Scheme } from "../lib/browse/data";
import Filters from "../lib/browse/Filters.svelte";
import HospitalsLayerControl from "../lib/browse/HospitalsLayerControl.svelte";
import ImdLayerControl from "../lib/browse/ImdLayerControl.svelte";
import LocalAuthorityDistrictsLayerControl from "../lib/browse/LocalAuthorityDistrictsLayerControl.svelte";
import LocalPlanningAuthoritiesLayerControl from "../lib/browse/LocalPlanningAuthoritiesLayerControl.svelte";
import MrnLayerControl from "../lib/browse/MrnLayerControl.svelte";
Expand Down Expand Up @@ -179,6 +180,7 @@
</CollapsibleCard>
<CollapsibleCard label="Census">
<CensusOutputAreaLayerControl />
<ImdLayerControl />
</CollapsibleCard>
<BaselayerSwitcher {style} />
</CollapsibleCard>
Expand Down

0 comments on commit 87b3323

Please sign in to comment.