Skip to content

Commit 0487472

Browse files
authored
Merge pull request #459 from wearepal/natmap-soil-mapview
NATMAP Soil carbon on map view
2 parents 736ae83 + 852b757 commit 0487472

File tree

6 files changed

+243
-70
lines changed

6 files changed

+243
-70
lines changed

app/javascript/projects/layer_palette.tsx

+20
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { IMDProperties } from './reify_layer/imd'
99
import { ProjectPermissions } from './project_editor'
1010
import { KewPointOptions } from './reify_layer/kew'
1111
import { seasonYearOptions } from './modelling/components/kew_samples_component'
12+
import { natmap_outputs } from './modelling/components/natmap_soil_component'
1213

1314
interface AddLayerButtonProps {
1415
prototype: Layer
@@ -330,6 +331,25 @@ export const LayerPalette = ({ addLayer, hide, dbModels, getTeamDatasets, teamNa
330331
/>)
331332
}
332333
</Section>
334+
{
335+
permissions.NATMAPSoil &&
336+
<Section title="Natmap Soil">
337+
<AddLayerButton
338+
addLayer={addLayer}
339+
prototype={{
340+
type: "WFSLayer",
341+
name: "Natmap Soil Carbon",
342+
layer: "cranfield_soil:NATMAPcarbon",
343+
attribution: "Cranfield University",
344+
propIdx: 0,
345+
visible: true,
346+
opacity: 1,
347+
fill: "jet"
348+
}}
349+
/>
350+
351+
</Section>
352+
}
333353
{
334354
dbModels.overlays.length > 0 &&
335355
<Section title="Overlays">

app/javascript/projects/modelling/components/natmap_soil_component.ts

+57-19
Original file line numberDiff line numberDiff line change
@@ -15,134 +15,172 @@ interface NatmapSoilOptions extends SelectControlOptions {
1515
key: string
1616
socket: Socket
1717
unit: string
18+
min: number
19+
max: number
1820
}
1921

20-
const natmap_outputs : NatmapSoilOptions[] = [
22+
export const natmap_outputs : NatmapSoilOptions[] = [
2123
{
2224
id: 0,
2325
name: 'Min Carbon stock 0-10cm (kg/m²)',
2426
key: 'MIN_STK_10',
2527
socket: numericDataSocket,
26-
unit: 'kg/m^2'
28+
unit: 'kg/m^2',
29+
min: 0,
30+
max: 82.32000000000
2731
},
2832
{
2933
id: 1,
3034
name: 'Max Carbon stock 0-10cm (kg/m²)',
3135
key: 'MAX_STK_10',
3236
socket: numericDataSocket,
33-
unit: 'kg/m^2'
37+
unit: 'kg/m^2',
38+
min: 0,
39+
max: 95.13000000000
3440
},
3541
{
3642
id: 2,
3743
name: 'Min Carbon stock 0-15cm (kg/m²)',
3844
key: 'MIN_STK_15',
3945
socket: numericDataSocket,
40-
unit: 'kg/m^2'
46+
unit: 'kg/m^2',
47+
min: 0,
48+
max: 59.64000000000
4149
},
4250
{
4351
id: 3,
4452
name: 'Max Carbon stock 0-15cm (kg/m²)',
4553
key: 'MAX_STK_15',
4654
socket: numericDataSocket,
47-
unit: 'kg/m^2'
55+
unit: 'kg/m^2',
56+
min: 0,
57+
max: 59.64000000000
4858
},
4959
{
5060
id: 4,
5161
name: 'Min Carbon stock 0-30cm (kg/m²)',
5262
key: 'MIN_STK_30',
5363
socket: numericDataSocket,
54-
unit: 'kg/m^2'
64+
unit: 'kg/m^2',
65+
min: 0,
66+
max: 35.45000000000
5567
},
5668
{
5769
id: 5,
5870
name: 'Max Carbon stock 0-30cm (kg/m²)',
5971
key: 'MAX_STK_30',
6072
socket: numericDataSocket,
61-
unit: 'kg/m^2'
73+
unit: 'kg/m^2',
74+
min: 0,
75+
max: 63.23000000000
6276
},
6377
{
6478
id: 6,
6579
name: 'Average Carbon stock 0-30cm (kg/m²)',
6680
key: 'AV_STK_30',
6781
socket: numericDataSocket,
68-
unit: 'kg/m^2'
82+
unit: 'kg/m^2',
83+
min: 0,
84+
max: 51.07000000000
6985
},
7086
{
7187
id: 7,
7288
name: 'Average Carbon stock 30-100cm (kg/m²)',
7389
key: 'AV_STK_100',
7490
socket: numericDataSocket,
75-
unit: 'kg/m^2'
91+
unit: 'kg/m^2',
92+
min: 0,
93+
max: 86.19000000000
7694
},
7795
{
7896
id: 8,
7997
name: 'Average Carbon stock 100-150cm (kg/m²)',
8098
key: 'AV_STK_150',
8199
socket: numericDataSocket,
82-
unit: 'kg/m^2'
100+
unit: 'kg/m^2',
101+
min: 0,
102+
max: 59.64000000000
83103
},
84104
{
85105
id: 9,
86106
name: 'Average Organic Carbon 0-30cm (%)',
87107
key: 'AV_OC_30',
88108
socket: numericDataSocket,
89-
unit: '%'
109+
unit: '%',
110+
min: 0,
111+
max: 100
90112
},
91113
{
92114
id: 10,
93115
name: 'Min Organic Carbon 0-30cm (%)',
94116
key: 'MIN_OC_30',
95117
socket: numericDataSocket,
96-
unit: '%'
118+
unit: '%',
119+
min: 0,
120+
max: 100
97121
},
98122
{
99123
id: 11,
100124
name: 'Max Organic Carbon 0-30cm (%)',
101125
key: 'MAX_OC_30',
102126
socket: numericDataSocket,
103-
unit: '%'
127+
unit: '%',
128+
min: 0,
129+
max: 100
104130
},
105131
{
106132
id: 12,
107133
name: 'Average Organic Carbon 30-100cm (%)',
108134
key: 'AV_OC_100',
109135
socket: numericDataSocket,
110-
unit: '%'
136+
unit: '%',
137+
min: 0,
138+
max: 100
111139
},
112140
{
113141
id: 13,
114142
name: 'Min Organic Carbon 30-100cm (%)',
115143
key: 'MIN_OC_100',
116144
socket: numericDataSocket,
117-
unit: '%'
145+
unit: '%',
146+
min: 0,
147+
max: 100
118148
},
119149
{
120150
id: 14,
121151
name: 'Max Organic Carbon 30-100cm (%)',
122152
key: 'MAX_OC_100',
123153
socket: numericDataSocket,
124-
unit: '%'
154+
unit: '%',
155+
min: 0,
156+
max: 100
125157
},
126158
{
127159
id: 15,
128160
name: 'Average Organic Carbon 100-150cm (%)',
129161
key: 'AV_OC_150',
130162
socket: numericDataSocket,
131-
unit: '%'
163+
unit: '%',
164+
min: 0,
165+
max: 100
132166
},
133167
{
134168
id: 16,
135169
name: 'Min Organic Carbon 100-150cm (%)',
136170
key: 'MIN_OC_150',
137171
socket: numericDataSocket,
138-
unit: '%'
172+
unit: '%',
173+
min: 0,
174+
max: 100
139175
},
140176
{
141177
id: 17,
142178
name: 'Max Organic Carbon 100-150cm (%)',
143179
key: 'MAX_OC_150',
144180
socket: numericDataSocket,
145-
unit: '%'
181+
unit: '%',
182+
min: 0,
183+
max: 100
146184
}
147185

148186
]

app/javascript/projects/reify_layer/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { reifyGeoserverWMSLayer } from './geoserver'
1818
import { reifyKewLayer, reifyKewPointLayer } from './kew'
1919
import { reifyOrvalLayer } from './orval'
2020
import { reifyIMDLayer } from './imd'
21+
import { reifyWFSLayer } from './wfs'
2122

2223
export const reifyLayer = (layer: Layer, existingLayer: BaseLayer | null, dbModels: DBModels, map: Map, modelOutputCache: ModelOutputCache, DatasetCache: DatasetCache, loadteamDataset: (layer: DatasetLayer) => void): BaseLayer => {
2324
const layerType = layer.type
@@ -38,6 +39,7 @@ export const reifyLayer = (layer: Layer, existingLayer: BaseLayer | null, dbMode
3839
case "ORValLayer": return reifyOrvalLayer(layer, existingLayer, map)
3940
case "IMDLayer": return reifyIMDLayer(layer, existingLayer, map)
4041
case "KewPointLayer": return reifyKewPointLayer(layer, existingLayer, map)
42+
case "WFSLayer": return reifyWFSLayer(layer, existingLayer, map)
4143
default: {
4244
// Ensure this switch statement is exhaustive
4345
const unreachable: never = layerType
+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import BaseLayer from "ol/layer/Base"
2+
import { WFSLayer } from "../state"
3+
import GeoJSON from "ol/format/GeoJSON"
4+
import Map from "ol/Map"
5+
import VectorLayer from "ol/layer/Vector"
6+
import { memoize } from "lodash"
7+
import VectorSource from "ol/source/Vector"
8+
import { bbox } from "ol/loadingstrategy"
9+
import { Fill, Stroke, Style } from "ol/style"
10+
import { natmap_outputs } from "../modelling/components/natmap_soil_component"
11+
import { findColor } from "../analysis_panel_tools/subsection"
12+
import { getColorStops } from "./model_output"
13+
14+
const getSource = memoize((id: string, attribution: undefined | string) => {
15+
16+
const store = id.split(":")[0]
17+
18+
const source = new VectorSource({
19+
url: extent => `https://landscapes.wearepal.ai/geoserver/${store}/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=${id}&outputFormat=application/json&bbox=${extent.join(',')},EPSG:3857&crs=EPSG:3857`,
20+
format: new GeoJSON({
21+
extractGeometryName: true
22+
}),
23+
strategy: bbox,
24+
attributions: attribution
25+
})
26+
27+
return source
28+
29+
})
30+
31+
const getStyle = (layer: WFSLayer, colMap: any[]) => (
32+
(feature) => {
33+
34+
const propIdx = layer.propIdx
35+
const prop = natmap_outputs[propIdx]
36+
const val = feature.get(prop.key)
37+
const [min, max] = [prop.min, prop.max]
38+
39+
const normalisedValue = prop.min > prop.max ? 1 - (val - min) / (max - min) : (val - min) / (max - min)
40+
const col = findColor(normalisedValue, colMap)
41+
42+
return new Style({
43+
fill: new Fill({ color: `rgba(${col[0]}, ${col[1]}, ${col[2]}, 1)`})
44+
})
45+
46+
}
47+
)
48+
49+
export function reifyWFSLayer (layer: WFSLayer, existingLayer: BaseLayer | null, map: Map) {
50+
51+
const colMap = getColorStops(layer.fill === "heatmap" ? "jet" : (layer.fill === "greyscale" ? "greys" : layer.fill), 100).reverse()
52+
53+
const vectLayer = new VectorLayer({
54+
source: getSource(layer.layer, layer.attribution),
55+
style: getStyle(layer, colMap),
56+
})
57+
58+
return vectLayer
59+
60+
}

0 commit comments

Comments
 (0)