Skip to content

Commit 5b18879

Browse files
committed
fix(spp_gis_indicators): fix manual classification breaks and constraint trigger
Move manual classification check before empty-data early return so manual_breaks can be computed without any imported indicator data. Add classification_method to @api.constrains so the validator fires when the method is changed to "manual" without touching manual_breaks.
1 parent 5e64462 commit 5b18879

34 files changed

Lines changed: 968 additions & 575 deletions

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ fastapi>=0.110.0
99
geojson
1010
httpx
1111
jwcrypto
12+
libhxl
1213
numpy>=1.22.2
1314
openpyxl
1415
parse-accept-language

spp_gis_indicators/README.rst

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ OpenSPP GIS Indicators
2020
.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png
2121
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
2222
:alt: License: LGPL-3
23-
.. |badge3| image:: https://img.shields.io/badge/github-OpenSPP%2Fopenspp--modules-lightgray.png?logo=github
24-
:target: https://github.com/OpenSPP/openspp-modules/tree/19.0/spp_gis_indicators
25-
:alt: OpenSPP/openspp-modules
23+
.. |badge3| image:: https://img.shields.io/badge/github-OpenSPP%2FOpenSPP2-lightgray.png?logo=github
24+
:target: https://github.com/OpenSPP/OpenSPP2/tree/19.0/spp_gis_indicators
25+
:alt: OpenSPP/OpenSPP2
2626

2727
|badge1| |badge2| |badge3|
2828

@@ -35,34 +35,34 @@ legend generation.
3535
Key Capabilities
3636
~~~~~~~~~~~~~~~~
3737

38-
- Define indicator layer configurations that link CEL variables to
39-
color scales and classification methods
40-
- Classify continuous indicator values into discrete color classes
41-
using quantile, equal interval, or manual breaks
42-
- Apply preset ColorBrewer color scales (sequential, diverging,
43-
categorical) or define custom scales
44-
- Compute break values automatically based on actual data distribution
45-
- Generate HTML legends showing color-to-value mappings
46-
- Map area features to colors for choropleth rendering in GIS data
47-
layers
48-
- Filter indicators by period and hazard incident context
38+
- Define indicator layer configurations that link CEL variables to color
39+
scales and classification methods
40+
- Classify continuous indicator values into discrete color classes using
41+
quantile, equal interval, or manual breaks
42+
- Apply preset ColorBrewer color scales (sequential, diverging,
43+
categorical) or define custom scales
44+
- Compute break values automatically based on actual data distribution
45+
- Generate HTML legends showing color-to-value mappings
46+
- Map area features to colors for choropleth rendering in GIS data
47+
layers
48+
- Filter indicators by period and hazard incident context
4949

5050
Key Models
5151
~~~~~~~~~~
5252

53-
+-----------------------------+---------------------------------------+
54-
| Model | Description |
55-
+=============================+=======================================+
56-
| ``spp.gis.indicator.layer`` | Configuration linking a CEL variable |
57-
| | to color scale and classification |
58-
| | settings |
59-
+-----------------------------+---------------------------------------+
60-
| ``spp.gis.color.scale`` | Color scheme definition with JSON |
61-
| | array of hex colors |
62-
+-----------------------------+---------------------------------------+
63-
| ``spp.gis.data.layer`` | Extended with ``choropleth`` geo |
64-
| | representation option |
65-
+-----------------------------+---------------------------------------+
53+
+-----------------------------+----------------------------------------+
54+
| Model | Description |
55+
+=============================+========================================+
56+
| ``spp.gis.indicator.layer`` | Configuration linking a CEL variable |
57+
| | to color scale and classification |
58+
| | settings |
59+
+-----------------------------+----------------------------------------+
60+
| ``spp.gis.color.scale`` | Color scheme definition with JSON |
61+
| | array of hex colors |
62+
+-----------------------------+----------------------------------------+
63+
| ``spp.gis.data.layer`` | Extended with ``choropleth`` geo |
64+
| | representation option |
65+
+-----------------------------+----------------------------------------+
6666

6767
Configuration
6868
~~~~~~~~~~~~~
@@ -81,8 +81,8 @@ After installing:
8181
UI Location
8282
~~~~~~~~~~~
8383

84-
- **Menu**: Settings > GIS Configuration > Indicator Layers
85-
- **Menu**: Settings > GIS Configuration > Color Scales
84+
- **Menu**: Settings > GIS Configuration > Indicator Layers
85+
- **Menu**: Settings > GIS Configuration > Color Scales
8686

8787
Security
8888
~~~~~~~~
@@ -98,13 +98,13 @@ Group Access
9898
Extension Points
9999
~~~~~~~~~~~~~~~~
100100

101-
- Override ``_compute_quantile_breaks()`` or
102-
``_compute_equal_interval_breaks()`` in ``spp.gis.indicator.layer``
103-
to add custom classification algorithms
104-
- Inherit ``spp.gis.color.scale`` and override
105-
``get_color_for_value()`` to implement custom color mapping logic
106-
- Extend ``spp.gis.indicator.layer._get_indicator_values()`` to support
107-
additional data sources beyond ``spp.hxl.area.indicator``
101+
- Override ``_compute_quantile_breaks()`` or
102+
``_compute_equal_interval_breaks()`` in ``spp.gis.indicator.layer`` to
103+
add custom classification algorithms
104+
- Inherit ``spp.gis.color.scale`` and override ``get_color_for_value()``
105+
to implement custom color mapping logic
106+
- Extend ``spp.gis.indicator.layer._get_indicator_values()`` to support
107+
additional data sources beyond ``spp.hxl.area.indicator``
108108

109109
Dependencies
110110
~~~~~~~~~~~~
@@ -124,10 +124,10 @@ Dependencies
124124
Bug Tracker
125125
===========
126126

127-
Bugs are tracked on `GitHub Issues <https://github.com/OpenSPP/openspp-modules/issues>`_.
127+
Bugs are tracked on `GitHub Issues <https://github.com/OpenSPP/OpenSPP2/issues>`_.
128128
In case of trouble, please check there if your issue has already been reported.
129129
If you spotted it first, help us to smash it by providing a detailed and welcomed
130-
`feedback <https://github.com/OpenSPP/openspp-modules/issues/new?body=module:%20spp_gis_indicators%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
130+
`feedback <https://github.com/OpenSPP/OpenSPP2/issues/new?body=module:%20spp_gis_indicators%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
131131

132132
Do not contact contributors directly about support or help with technical issues.
133133

@@ -142,6 +142,6 @@ Authors
142142
Maintainers
143143
-----------
144144

145-
This module is part of the `OpenSPP/openspp-modules <https://github.com/OpenSPP/openspp-modules/tree/19.0/spp_gis_indicators>`_ project on GitHub.
145+
This module is part of the `OpenSPP/OpenSPP2 <https://github.com/OpenSPP/OpenSPP2/tree/19.0/spp_gis_indicators>`_ project on GitHub.
146146

147147
You are welcome to contribute.
Lines changed: 126 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,140 @@
1-
<?xml version="1.0" encoding="utf-8"?>
2-
<odoo>
3-
<data noupdate="1">
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<odoo noupdate="1">
3+
<!-- Sequential Color Scales -->
44

5-
<!-- Sequential Color Scales -->
5+
<record id="color_scale_blues" model="spp.gis.color.scale">
6+
<field name="name">Blues (Sequential)</field>
7+
<field name="scale_type">sequential</field>
8+
<field
9+
name="colors_json"
10+
>["#f7fbff", "#deebf7", "#c6dbef", "#9ecae1", "#6baed6", "#4292c6", "#2171b5", "#08519c", "#08306b"]</field>
11+
<field
12+
name="description"
13+
>Sequential blue color scale from light to dark. Good for showing increasing values like population density or service coverage.</field>
14+
<field name="sequence">10</field>
15+
</record>
616

7-
<record id="color_scale_blues" model="spp.gis.color.scale">
8-
<field name="name">Blues (Sequential)</field>
9-
<field name="scale_type">sequential</field>
10-
<field name="colors_json">["#f7fbff", "#deebf7", "#c6dbef", "#9ecae1", "#6baed6", "#4292c6", "#2171b5", "#08519c", "#08306b"]</field>
11-
<field name="description">Sequential blue color scale from light to dark. Good for showing increasing values like population density or service coverage.</field>
12-
<field name="sequence">10</field>
13-
</record>
17+
<record id="color_scale_greens" model="spp.gis.color.scale">
18+
<field name="name">Greens (Sequential)</field>
19+
<field name="scale_type">sequential</field>
20+
<field
21+
name="colors_json"
22+
>["#f7fcf5", "#e5f5e0", "#c7e9c0", "#a1d99b", "#74c476", "#41ab5d", "#238b45", "#006d2c", "#00441b"]</field>
23+
<field
24+
name="description"
25+
>Sequential green color scale from light to dark. Good for showing environmental or health indicators.</field>
26+
<field name="sequence">20</field>
27+
</record>
1428

15-
<record id="color_scale_greens" model="spp.gis.color.scale">
16-
<field name="name">Greens (Sequential)</field>
17-
<field name="scale_type">sequential</field>
18-
<field name="colors_json">["#f7fcf5", "#e5f5e0", "#c7e9c0", "#a1d99b", "#74c476", "#41ab5d", "#238b45", "#006d2c", "#00441b"]</field>
19-
<field name="description">Sequential green color scale from light to dark. Good for showing environmental or health indicators.</field>
20-
<field name="sequence">20</field>
21-
</record>
29+
<record id="color_scale_reds" model="spp.gis.color.scale">
30+
<field name="name">Reds (Sequential)</field>
31+
<field name="scale_type">sequential</field>
32+
<field
33+
name="colors_json"
34+
>["#fff5f0", "#fee0d2", "#fcbba1", "#fc9272", "#fb6a4a", "#ef3b2c", "#cb181d", "#a50f15", "#67000d"]</field>
35+
<field
36+
name="description"
37+
>Sequential red color scale from light to dark. Good for showing risk, danger, or negative indicators.</field>
38+
<field name="sequence">30</field>
39+
</record>
2240

23-
<record id="color_scale_reds" model="spp.gis.color.scale">
24-
<field name="name">Reds (Sequential)</field>
25-
<field name="scale_type">sequential</field>
26-
<field name="colors_json">["#fff5f0", "#fee0d2", "#fcbba1", "#fc9272", "#fb6a4a", "#ef3b2c", "#cb181d", "#a50f15", "#67000d"]</field>
27-
<field name="description">Sequential red color scale from light to dark. Good for showing risk, danger, or negative indicators.</field>
28-
<field name="sequence">30</field>
29-
</record>
41+
<record id="color_scale_oranges" model="spp.gis.color.scale">
42+
<field name="name">Oranges (Sequential)</field>
43+
<field name="scale_type">sequential</field>
44+
<field
45+
name="colors_json"
46+
>["#fff5eb", "#fee6ce", "#fdd0a2", "#fdae6b", "#fd8d3c", "#f16913", "#d94801", "#a63603", "#7f2704"]</field>
47+
<field
48+
name="description"
49+
>Sequential orange color scale from light to dark. Good for showing moderate risk or attention areas.</field>
50+
<field name="sequence">40</field>
51+
</record>
3052

31-
<record id="color_scale_oranges" model="spp.gis.color.scale">
32-
<field name="name">Oranges (Sequential)</field>
33-
<field name="scale_type">sequential</field>
34-
<field name="colors_json">["#fff5eb", "#fee6ce", "#fdd0a2", "#fdae6b", "#fd8d3c", "#f16913", "#d94801", "#a63603", "#7f2704"]</field>
35-
<field name="description">Sequential orange color scale from light to dark. Good for showing moderate risk or attention areas.</field>
36-
<field name="sequence">40</field>
37-
</record>
53+
<record id="color_scale_purples" model="spp.gis.color.scale">
54+
<field name="name">Purples (Sequential)</field>
55+
<field name="scale_type">sequential</field>
56+
<field
57+
name="colors_json"
58+
>["#fcfbfd", "#efedf5", "#dadaeb", "#bcbddc", "#9e9ac8", "#807dba", "#6a51a3", "#54278f", "#3f007d"]</field>
59+
<field
60+
name="description"
61+
>Sequential purple color scale from light to dark. Good for showing education or program enrollment indicators.</field>
62+
<field name="sequence">50</field>
63+
</record>
3864

39-
<record id="color_scale_purples" model="spp.gis.color.scale">
40-
<field name="name">Purples (Sequential)</field>
41-
<field name="scale_type">sequential</field>
42-
<field name="colors_json">["#fcfbfd", "#efedf5", "#dadaeb", "#bcbddc", "#9e9ac8", "#807dba", "#6a51a3", "#54278f", "#3f007d"]</field>
43-
<field name="description">Sequential purple color scale from light to dark. Good for showing education or program enrollment indicators.</field>
44-
<field name="sequence">50</field>
45-
</record>
65+
<!-- Diverging Color Scales -->
4666

47-
<!-- Diverging Color Scales -->
67+
<record id="color_scale_rdylgn" model="spp.gis.color.scale">
68+
<field name="name">Red-Yellow-Green (Diverging)</field>
69+
<field name="scale_type">diverging</field>
70+
<field
71+
name="colors_json"
72+
>["#d73027", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#d9ef8b", "#a6d96a", "#66bd63", "#1a9850"]</field>
73+
<field
74+
name="description"
75+
>Diverging scale from red (negative) through yellow to green (positive). Good for showing progress against targets or deviations from a norm.</field>
76+
<field name="sequence">60</field>
77+
</record>
4878

49-
<record id="color_scale_rdylgn" model="spp.gis.color.scale">
50-
<field name="name">Red-Yellow-Green (Diverging)</field>
51-
<field name="scale_type">diverging</field>
52-
<field name="colors_json">["#d73027", "#f46d43", "#fdae61", "#fee08b", "#ffffbf", "#d9ef8b", "#a6d96a", "#66bd63", "#1a9850"]</field>
53-
<field name="description">Diverging scale from red (negative) through yellow to green (positive). Good for showing progress against targets or deviations from a norm.</field>
54-
<field name="sequence">60</field>
55-
</record>
79+
<record id="color_scale_rdbu" model="spp.gis.color.scale">
80+
<field name="name">Red-Blue (Diverging)</field>
81+
<field name="scale_type">diverging</field>
82+
<field
83+
name="colors_json"
84+
>["#67001f", "#b2182b", "#d6604d", "#f4a582", "#fddbc7", "#d1e5f0", "#92c5de", "#4393c3", "#2166ac", "#053061"]</field>
85+
<field
86+
name="description"
87+
>Diverging scale from red to blue. Good for showing opposing conditions or bidirectional change.</field>
88+
<field name="sequence">70</field>
89+
</record>
5690

57-
<record id="color_scale_rdbu" model="spp.gis.color.scale">
58-
<field name="name">Red-Blue (Diverging)</field>
59-
<field name="scale_type">diverging</field>
60-
<field name="colors_json">["#67001f", "#b2182b", "#d6604d", "#f4a582", "#fddbc7", "#d1e5f0", "#92c5de", "#4393c3", "#2166ac", "#053061"]</field>
61-
<field name="description">Diverging scale from red to blue. Good for showing opposing conditions or bidirectional change.</field>
62-
<field name="sequence">70</field>
63-
</record>
91+
<record id="color_scale_spectral" model="spp.gis.color.scale">
92+
<field name="name">Spectral (Diverging)</field>
93+
<field name="scale_type">diverging</field>
94+
<field
95+
name="colors_json"
96+
>["#9e0142", "#d53e4f", "#f46d43", "#fdae61", "#fee08b", "#e6f598", "#abdda4", "#66c2a5", "#3288bd", "#5e4fa2"]</field>
97+
<field
98+
name="description"
99+
>Spectral diverging scale across the color spectrum. Good for showing complex diverging patterns.</field>
100+
<field name="sequence">80</field>
101+
</record>
64102

65-
<record id="color_scale_spectral" model="spp.gis.color.scale">
66-
<field name="name">Spectral (Diverging)</field>
67-
<field name="scale_type">diverging</field>
68-
<field name="colors_json">["#9e0142", "#d53e4f", "#f46d43", "#fdae61", "#fee08b", "#e6f598", "#abdda4", "#66c2a5", "#3288bd", "#5e4fa2"]</field>
69-
<field name="description">Spectral diverging scale across the color spectrum. Good for showing complex diverging patterns.</field>
70-
<field name="sequence">80</field>
71-
</record>
103+
<record id="color_scale_brbg" model="spp.gis.color.scale">
104+
<field name="name">Brown-Green (Diverging)</field>
105+
<field name="scale_type">diverging</field>
106+
<field
107+
name="colors_json"
108+
>["#8c510a", "#bf812d", "#dfc27d", "#f6e8c3", "#f5f5f5", "#c7eae5", "#80cdc1", "#35978f", "#01665e"]</field>
109+
<field
110+
name="description"
111+
>Diverging scale from brown to green. Good for environmental indicators or land use changes.</field>
112+
<field name="sequence">90</field>
113+
</record>
72114

73-
<record id="color_scale_brbg" model="spp.gis.color.scale">
74-
<field name="name">Brown-Green (Diverging)</field>
75-
<field name="scale_type">diverging</field>
76-
<field name="colors_json">["#8c510a", "#bf812d", "#dfc27d", "#f6e8c3", "#f5f5f5", "#c7eae5", "#80cdc1", "#35978f", "#01665e"]</field>
77-
<field name="description">Diverging scale from brown to green. Good for environmental indicators or land use changes.</field>
78-
<field name="sequence">90</field>
79-
</record>
115+
<!-- Categorical Color Scales -->
80116

81-
<!-- Categorical Color Scales -->
117+
<record id="color_scale_set1" model="spp.gis.color.scale">
118+
<field name="name">Set1 (Categorical)</field>
119+
<field name="scale_type">categorical</field>
120+
<field
121+
name="colors_json"
122+
>["#e41a1c", "#377eb8", "#4daf4a", "#984ea3", "#ff7f00", "#ffff33", "#a65628", "#f781bf"]</field>
123+
<field
124+
name="description"
125+
>Categorical color set with distinct colors. Good for showing different types or categories.</field>
126+
<field name="sequence">100</field>
127+
</record>
82128

83-
<record id="color_scale_set1" model="spp.gis.color.scale">
84-
<field name="name">Set1 (Categorical)</field>
85-
<field name="scale_type">categorical</field>
86-
<field name="colors_json">["#e41a1c", "#377eb8", "#4daf4a", "#984ea3", "#ff7f00", "#ffff33", "#a65628", "#f781bf"]</field>
87-
<field name="description">Categorical color set with distinct colors. Good for showing different types or categories.</field>
88-
<field name="sequence">100</field>
89-
</record>
90-
91-
<record id="color_scale_paired" model="spp.gis.color.scale">
92-
<field name="name">Paired (Categorical)</field>
93-
<field name="scale_type">categorical</field>
94-
<field name="colors_json">["#a6cee3", "#1f78b4", "#b2df8a", "#33a02c", "#fb9a99", "#e31a1c", "#fdbf6f", "#ff7f00"]</field>
95-
<field name="description">Paired categorical colors with light and dark variants. Good for comparing similar categories.</field>
96-
<field name="sequence">110</field>
97-
</record>
98-
99-
</data>
129+
<record id="color_scale_paired" model="spp.gis.color.scale">
130+
<field name="name">Paired (Categorical)</field>
131+
<field name="scale_type">categorical</field>
132+
<field
133+
name="colors_json"
134+
>["#a6cee3", "#1f78b4", "#b2df8a", "#33a02c", "#fb9a99", "#e31a1c", "#fdbf6f", "#ff7f00"]</field>
135+
<field
136+
name="description"
137+
>Paired categorical colors with light and dark variants. Good for comparing similar categories.</field>
138+
<field name="sequence">110</field>
139+
</record>
100140
</odoo>

spp_gis_indicators/models/color_scale.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ def _check_colors_json(self):
8888
if not color.startswith("#") or len(color) not in (4, 7):
8989
raise ValidationError(
9090
_(
91-
"Invalid hex color format: %s. " "Expected #RGB or #RRGGBB",
91+
"Invalid hex color format: %s. Expected #RGB or #RRGGBB",
9292
color,
9393
)
9494
)

0 commit comments

Comments
 (0)