Add Original Land Use (Order) to Key

Copied code from Current Land Use (Land Use Category) to automatically calculate the Land Use Order for Original Land Use and then visualise it on the map. #1219
This commit is contained in:
Mike Simpson 2023-08-03 16:42:12 +01:00
parent 0db7ceb4e9
commit 602449cf58
12 changed files with 220 additions and 2 deletions

View File

@ -913,6 +913,83 @@
<LineSymbolizer stroke="#888" stroke-width="3.0"/> <LineSymbolizer stroke="#888" stroke-width="3.0"/>
</Rule> </Rule>
</Style> </Style>
<Style name="original_landuse">
<Rule>
<Filter>[typology_original_use_order] = "Agriculture And Fisheries"</Filter>
<PolygonSymbolizer fill="#73ccd1" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Minerals"</Filter>
<PolygonSymbolizer fill="#45cce3" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Unclassified, presumed non-residential"</Filter>
<PolygonSymbolizer fill="#6c6f8e" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Recreation And Leisure"</Filter>
<PolygonSymbolizer fill="#ffbfbf" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Transport"</Filter>
<PolygonSymbolizer fill="#b3de69" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Utilities And Infrastructure"</Filter>
<PolygonSymbolizer fill="#cccccc" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Residential" and not ([typology_original_use_order] = "Garden buildings") and not ([typology_original_use_order] = "Hotels, boarding and guest houses") and not ([typology_original_use_verified])</Filter>
<PolygonSymbolizer fill="#252aa6" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Residential" and not ([typology_original_use_order] = "Garden buildings") and not ([typology_original_use_order] = "Hotels, boarding and guest houses") and ([typology_original_use_verified])</Filter>
<PolygonSymbolizer fill="#7025a6" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Residential" and [typology_original_use_order] = "Hotels, boarding and guest houses"</Filter>
<PolygonSymbolizer fill="#3c4194" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Residential" and [typology_original_use_order] = "Garden buildings" </Filter>
<PolygonSymbolizer fill="#1157fa" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Community Services"</Filter>
<PolygonSymbolizer fill="#fa667d" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Retail"</Filter>
<PolygonSymbolizer fill="#ff8c00" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Industry And Business"</Filter>
<PolygonSymbolizer fill="#f5f58f" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Vacant And Derelict"</Filter>
<PolygonSymbolizer fill="#ffffff" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Defence"</Filter>
<PolygonSymbolizer fill="#898944" />
</Rule>
<Rule>
<Filter>[typology_original_use_order] = "Mixed Use"</Filter>
<PolygonSymbolizer fill="#e5050d" />
</Rule>
<Rule>
<MaxScaleDenominator>8530</MaxScaleDenominator>
<MinScaleDenominator>4264</MinScaleDenominator>
<LineSymbolizer stroke="#888" stroke-width="0.8"/>
</Rule>
<Rule>
<MaxScaleDenominator>4264</MaxScaleDenominator>
<MinScaleDenominator>0</MinScaleDenominator>
<LineSymbolizer stroke="#888" stroke-width="3.0"/>
</Rule>
</Style>
<Style name="disaster_severity"> <Style name="disaster_severity">
<Rule> <Rule>
<Filter>[disaster_severity] = "Building destroyed"</Filter> <Filter>[disaster_severity] = "Building destroyed"</Filter>

View File

@ -965,6 +965,14 @@ export const buildingAttributesConfig = valueType<DataFieldConfig>()({ /* eslint
verify: true verify: true
}, },
typology_original_use : { typology_original_use : {
edit: true,
derivedEdit: true,
verify: true
},
typology_original_use_verified: {
edit: true,
},
typology_original_use_order : {
edit: true, edit: true,
verify: true verify: true
}, },

View File

@ -9,7 +9,7 @@ import { ArgumentError } from '../../errors/general';
import { updateLandUse } from './landUse'; import { updateLandUse } from './landUse';
/** /**
* Process land use classifications - derive land use order from land use groups * Process current land use classifications - derive land use order from land use groups
*/ */
async function processCurrentLandUseClassifications( async function processCurrentLandUseClassifications(
buildingId: number, buildingId: number,
@ -40,6 +40,37 @@ async function processCurrentLandUseClassifications(
} }
} }
/**
* Process original land use classifications - derive land use order from land use groups
*/
async function processOriginalLandUseClassifications(
buildingId: number,
buildingUpdate: Partial<BuildingAttributes>,
t?: ITask<any>
): Promise<any> {
const currentBuildingData = await getBuildingData(buildingId);
try {
const currentLandUseUpdate = await updateLandUse(
{
landUseGroup: currentBuildingData.typology_original_use,
landUseOrder: currentBuildingData.typology_original_use_order
}, {
landUseGroup: buildingUpdate.typology_original_use
}
);
return Object.assign({}, buildingUpdate, {
typology_original_use: currentLandUseUpdate.landUseGroup,
typology_original_use_order: currentLandUseUpdate.landUseOrder,
});
} catch (error) {
if(error instanceof ArgumentError && error.argumentName === 'landUseUpdate') {
error.argumentName = 'buildingUpdate';
}
throw error;
}
}
/** /**
* Process Dynamics data - check field relationships and sort demolished buildings by construction date * Process Dynamics data - check field relationships and sort demolished buildings by construction date
@ -81,6 +112,9 @@ export async function processBuildingUpdate(buildingId: number, {attributes, use
if(hasAnyOwnProperty(attributes, ['current_landuse_group'])) { if(hasAnyOwnProperty(attributes, ['current_landuse_group'])) {
attributes = await processCurrentLandUseClassifications(buildingId, attributes, t); attributes = await processCurrentLandUseClassifications(buildingId, attributes, t);
} }
if(hasAnyOwnProperty(attributes, ['typology_original_use'])) {
attributes = await processOriginalLandUseClassifications(buildingId, attributes, t);
}
if(hasAnyOwnProperty(attributes, ['demolished_buildings', 'dynamics_has_demolished_buildings'])) { if(hasAnyOwnProperty(attributes, ['demolished_buildings', 'dynamics_has_demolished_buildings'])) {
attributes = await processDynamicsDemolishedBuildings(buildingId, attributes, t); attributes = await processDynamicsDemolishedBuildings(buildingId, attributes, t);
} }

View File

@ -99,7 +99,9 @@ const withCopyEdit: (wc: React.ComponentType<CategoryViewProps>) => DataContaine
'likes_total', 'likes_total',
'community_type_worth_keeping_total', 'community_type_worth_keeping_total',
'community_local_significance_total', 'community_local_significance_total',
'community_expected_planning_application_total' 'community_expected_planning_application_total',
'typology_original_use',
'typology_original_use_verified'
] ]
for (let key in dataFields) { for (let key in dataFields) {
let fieldName = props.building == undefined ? undefined : props.building[key]; let fieldName = props.building == undefined ? undefined : props.building[key];
@ -286,6 +288,13 @@ const withCopyEdit: (wc: React.ComponentType<CategoryViewProps>) => DataContaine
this.doSubmit(edits); this.doSubmit(edits);
} }
if (slug == 'typology_original_use'){
const edits = {
'typology_original_use_verified': true
};
this.doSubmit(edits);
}
console.log(slug + " verify button clicked") console.log(slug + " verify button clicked")
} }

View File

@ -138,6 +138,7 @@ const UseView: React.FunctionComponent<CategoryViewProps> = (props) => {
/> />
</> </>
} }
<hr/>
{ {
props.mode != 'view' && props.mode != 'view' &&
<div> <div>

View File

@ -35,6 +35,10 @@ const TypeView: React.FunctionComponent<CategoryViewProps> = (props) => {
e.preventDefault(); e.preventDefault();
props.onMapColourScale('building_attachment_form') props.onMapColourScale('building_attachment_form')
} }
const switchToLandUseMapStyle = (e) => {
e.preventDefault();
props.onMapColourScale('original_landuse')
}
return ( return (
<Fragment> <Fragment>
@ -216,6 +220,15 @@ const TypeView: React.FunctionComponent<CategoryViewProps> = (props) => {
} }
</DataEntryGroup> </DataEntryGroup>
<DataEntryGroup name="Original Use"> <DataEntryGroup name="Original Use">
{(props.mapColourScale == "original_landuse") ?
<button className={`map-switcher-inline enabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToClassificationMapStyle}>
{'Click to change map to show typology classification.'}
</button>
:
<button className={`map-switcher-inline disabled-state btn btn-outline btn-outline-dark ${darkLightTheme}`} onClick={switchToLandUseMapStyle}>
{"Click here to change map to original land use."}
</button>
}
<MultiDataEntry <MultiDataEntry
title={dataFields.typology_original_use.title} title={dataFields.typology_original_use.title}
slug="typology_original_use" slug="typology_original_use"
@ -267,6 +280,27 @@ const TypeView: React.FunctionComponent<CategoryViewProps> = (props) => {
/> />
</> </>
} }
<hr/>
{
props.mode != 'view' &&
<div>
<div className={`alert alert-dark`} role="alert" style={{ fontSize: 13, backgroundColor: "#f6f8f9" }}>
<i>
Below is a more general classification for the original land use of this building, automatically derived from the information above.
</i>
</div>
</div>
}
<DataEntry
title={dataFields.typology_original_use_order.title}
tooltip={dataFields.typology_original_use_order.tooltip}
slug="typology_original_use_order"
value={props.building.typology_original_use_order}
mode={props.mode}
disabled={true}
copy={props.copy}
onChange={props.onChange}
/>
</DataEntryGroup> </DataEntryGroup>
<DataEntryGroup name="Attachment/Adjacency"> <DataEntryGroup name="Attachment/Adjacency">
{(props.mapColourScale == "building_attachment_form") ? {(props.mapColourScale == "building_attachment_form") ?

View File

@ -348,6 +348,29 @@ export const categoryMapsConfig: {[key in Category]: CategoryMapDefinition[]} =
] ]
} }
}, },
{
mapStyle: 'original_landuse',
legend: {
title: 'Original Land Use',
elements: [
{ color: '#e5050d', text: 'Mixed Use' },
{ subtitle: 'Single use:'},
{ color: '#252aa6', text: 'Residential (unverified)' },
{ color: '#7025a6', text: 'Residential (verified)' },
{ color: '#ff8c00', text: 'Retail' },
{ color: '#f5f58f', text: 'Industry & Business' },
{ color: '#fa667d', text: 'Community Services' },
{ color: '#ffbfbf', text: 'Recreation & Leisure' },
{ color: '#b3de69', text: 'Transport' },
{ color: '#cccccc', text: 'Utilities & Infrastructure' },
{ color: '#898944', text: 'Defence' },
{ color: '#73ccd1', text: 'Agriculture' },
{ color: '#45cce3', text: 'Minerals' },
{ color: '#ffffff', text: 'Vacant & Derelict' },
{ color: '#6c6f8e', text: 'Unclassified, presumed non-residential' }
]
},
},
{ {
mapStyle: 'building_attachment_form', mapStyle: 'building_attachment_form',
legend: { legend: {

View File

@ -1833,6 +1833,17 @@ export const dataFields = { /* eslint-disable @typescript-eslint/camelcase */
tooltip: "Land use Groups as classified by [NLUD](https://www.gov.uk/government/statistics/national-land-use-database-land-use-and-land-cover-classification)", tooltip: "Land use Groups as classified by [NLUD](https://www.gov.uk/government/statistics/national-land-use-database-land-use-and-land-cover-classification)",
example: ["", ""], example: ["", ""],
}, },
typology_original_use_verified: {
category: Category.LandUse,
title: 'Has this land use been manually verified?',
example: true,
},
typology_original_use_order: {
category: Category.Typology,
title: "Original land use (order)",
tooltip: "Land use Order as classified by [NLUD](https://www.gov.uk/government/statistics/national-land-use-database-land-use-and-land-cover-classification)",
example: "",
},
typology_original_use_source_type: { typology_original_use_source_type: {
category: Category.Typology, category: Category.Typology,
title: "Source type", title: "Source type",

View File

@ -21,6 +21,7 @@ export type BuildingMapTileset =
'sust_dec' | 'sust_dec' |
'building_attachment_form' | 'building_attachment_form' |
'landuse' | 'landuse' |
'original_landuse' |
'dynamics_demolished_count' | 'dynamics_demolished_count' |
'disaster_severity' | 'disaster_severity' |
'team' | 'team' |

View File

@ -266,6 +266,15 @@ const LAYER_QUERIES = {
buildings buildings
WHERE WHERE
current_landuse_order IS NOT NULL`, current_landuse_order IS NOT NULL`,
original_landuse: `
SELECT
geometry_id,
typology_original_use_order,
typology_original_use[1] as typology_original_use,
typology_original_use_verified
FROM
buildings
WHERE typology_original_use IS NOT NULL`,
disaster_severity: ` disaster_severity: `
SELECT SELECT
geometry_id, geometry_id,

View File

@ -0,0 +1,2 @@
ALTER TABLE buildings DROP COLUMN IF EXISTS typology_original_use_order;
ALTER TABLE buildings DROP COLUMN IF NOT EXISTS typology_original_use_verified;

View File

@ -0,0 +1,9 @@
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_original_use_order text;
ALTER TABLE buildings ADD COLUMN IF NOT EXISTS typology_original_use_verified BOOLEAN NOT NULL DEFAULT FALSE;
UPDATE buildings as b
SET typology_original_use_verified = TRUE
FROM building_verification as v
WHERE b.building_id = v.building_id
AND v.attribute = 'current_landuse_group';