From 35aeab0218e7d8f4ce5bf2c9af72e588317c7258 Mon Sep 17 00:00:00 2001 From: andrea rota Date: Fri, 15 Mar 2024 11:35:55 +0000 Subject: [PATCH] pass through gap data (target/met) values with rounding to 4 decimal digits --- ...ndingTargetAndCurrentDataInGapDataViews.ts | 147 ++++++++++++++++++ .../scenario-features-gap-data.geo.entity.ts | 8 +- .../gap-analysis/item/component.tsx | 2 +- 3 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 api/apps/geoprocessing/src/migrations/geoprocessing/1710497811000-IncludeDecimalDigitsWhenRoundingTargetAndCurrentDataInGapDataViews.ts diff --git a/api/apps/geoprocessing/src/migrations/geoprocessing/1710497811000-IncludeDecimalDigitsWhenRoundingTargetAndCurrentDataInGapDataViews.ts b/api/apps/geoprocessing/src/migrations/geoprocessing/1710497811000-IncludeDecimalDigitsWhenRoundingTargetAndCurrentDataInGapDataViews.ts new file mode 100644 index 0000000000..16a0591827 --- /dev/null +++ b/api/apps/geoprocessing/src/migrations/geoprocessing/1710497811000-IncludeDecimalDigitsWhenRoundingTargetAndCurrentDataInGapDataViews.ts @@ -0,0 +1,147 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class IncludeDecimalDigitsWhenRoundingTargetAndCurrentDataInGapDataViews1710497811000 + implements MigrationInterface +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(` +drop view scenario_features_gap_data; + +create view scenario_features_gap_data as + with gap_data as ( + select + sfd.api_feature_id as feature_id, + scenario_id, + sum(total_area) total_area, + case when sum(current_pa) is not null + then sum(current_pa) + else 0 + end as met_area, + min(prop) as coverage_target + from scenario_features_data sfd + group by sfd.api_feature_id, feature_class_id, scenario_id) + select + scenario_id, + feature_id, + sum(total_area) as total_area, + sum(met_area) as met_area, + case + when sum(total_area) > 0 + then round(((sum(met_area)/sum(total_area))*100)::numeric, 4) + else 0 + end as met, + sum(total_area) * min(coverage_target) as coverage_target_area, + round((min(coverage_target) * 100)::numeric, 4) as coverage_target, + sum(met_area) >= (sum(total_area) * min(coverage_target)) as on_target + from gap_data + group by feature_id, scenario_id; + `); + + await queryRunner.query(` +drop view scenario_features_output_gap_data; + +create view scenario_features_output_gap_data as + with gap_data as ( + select + amount, + occurrences, + run_id, + sfd.api_feature_id as feature_id, + sfd.scenario_id, + osfd.total_area, + sfd.prop as coverage_target, + osfd.target as target_met + from output_scenarios_features_data osfd + inner join scenario_features_data sfd on osfd.scenario_features_id=sfd.id) + select + scenario_id, + feature_id, + sum(total_area) as total_area, + sum(amount) as met_area, + case + when sum(total_area) <> 0 and sum(total_area) is not null then + round(((sum(amount)/sum(total_area))*100)::numeric, 4) + else + 0 + end as met, + sum(occurrences) as met_occurrences, + sum(total_area) * min(coverage_target) as coverage_target_area, + round((min(coverage_target) * 100)::numeric, 4) as coverage_target, + bool_and(target_met) as on_target, + run_id + from gap_data + group by run_id, feature_id, scenario_id; + `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(` +drop view scenario_features_gap_data; + +create view scenario_features_gap_data as + with gap_data as ( + select + sfd.api_feature_id as feature_id, + scenario_id, + sum(total_area) total_area, + case when sum(current_pa) is not null + then sum(current_pa) + else 0 + end as met_area, + min(prop) as coverage_target + from scenario_features_data sfd + group by sfd.api_feature_id, feature_class_id, scenario_id) + select + scenario_id, + feature_id, + sum(total_area) as total_area, + sum(met_area) as met_area, + case + when sum(total_area) > 0 + then round((sum(met_area)/sum(total_area))*100) + else 0 + end as met, + sum(total_area) * min(coverage_target) as coverage_target_area, + round(min(coverage_target) * 100) as coverage_target, + sum(met_area) >= (sum(total_area) * min(coverage_target)) as on_target + from gap_data + group by feature_id, scenario_id; + `); + + await queryRunner.query(` + drop view scenario_features_output_gap_data; + + create view scenario_features_output_gap_data as + with gap_data as ( + select + amount, + occurrences, + run_id, + sfd.api_feature_id as feature_id, + sfd.scenario_id, + osfd.total_area, + sfd.prop as coverage_target, + osfd.target as target_met + from output_scenarios_features_data osfd + inner join scenario_features_data sfd on osfd.scenario_features_id=sfd.id) + select + scenario_id, + feature_id, + sum(total_area) as total_area, + sum(amount) as met_area, + case + when sum(total_area) <> 0 and sum(total_area) is not null then + round((sum(amount)/sum(total_area))*100) + else + 0 + end as met, + sum(occurrences) as met_occurrences, + sum(total_area) * min(coverage_target) as coverage_target_area, + round(min(coverage_target) * 100) as coverage_target, + bool_and(target_met) as on_target, + run_id + from gap_data + group by run_id, feature_id, scenario_id; + `); + } +} diff --git a/api/libs/features/src/scenario-features-gap-data.geo.entity.ts b/api/libs/features/src/scenario-features-gap-data.geo.entity.ts index a73a7f2d51..0266bbb7bc 100644 --- a/api/libs/features/src/scenario-features-gap-data.geo.entity.ts +++ b/api/libs/features/src/scenario-features-gap-data.geo.entity.ts @@ -20,7 +20,9 @@ export class ScenarioFeaturesGapData { metArea!: number; @ApiProperty() - @Column({ name: 'met' }) + // explicitly set type, otherwise TypeORM (v10, at least) will cast to integer + // TypeORM will still represent the value as string though (https://github.com/typeorm/typeorm/issues/873#issuecomment-328912050) + @Column({ name: 'met', type: 'double precision' }) met!: number; @ApiProperty() @@ -28,7 +30,9 @@ export class ScenarioFeaturesGapData { coverageTargetArea!: number; @ApiProperty() - @Column({ name: 'coverage_target' }) + // explicitly set type, otherwise TypeORM (v10, at least) will cast to integer + // TypeORM will still represent the value as string though (https://github.com/typeorm/typeorm/issues/873#issuecomment-328912050) + @Column({ name: 'coverage_target', type: 'double precision' }) coverageTarget!: number; @ApiProperty() diff --git a/app/components/gap-analysis/item/component.tsx b/app/components/gap-analysis/item/component.tsx index c53f21b6b9..0416b391c9 100644 --- a/app/components/gap-analysis/item/component.tsx +++ b/app/components/gap-analysis/item/component.tsx @@ -41,7 +41,7 @@ export const Item: React.FC = ({ }: ItemProps) => { const chartRef = useRef(null); const [chartEl, setChartEl] = useState(null); - const percentFormatter = useNumberFormatter({ style: 'percent' }); + const percentFormatter = useNumberFormatter({ style: 'percent', maximumFractionDigits: 4 }); const metStyles = useMemo(() => { if (chartEl) {