From cbb05bed5227ce368667138d8d731a1a6157c65a Mon Sep 17 00:00:00 2001 From: Tim Sutton Date: Mon, 16 Sep 2024 12:14:25 +0100 Subject: [PATCH 1/3] Tidy up imports and remote dep on json validator for now --- geest/__init__.py | 2 +- geest/gui/__init__.py | 2 ++ geest/gui/geest_treeview.py | 15 +++++++++++---- geest/gui/setup_panel.py | 2 +- geest/gui/tree_panel.py | 24 ++++++++++++++++++++---- geest/{ => resources}/geest2.ods | Bin geest/resources/model.json | 30 +++++++++++++++++++----------- 7 files changed, 54 insertions(+), 21 deletions(-) rename geest/{ => resources}/geest2.ods (100%) diff --git a/geest/__init__.py b/geest/__init__.py index eb84818d..a9b39216 100644 --- a/geest/__init__.py +++ b/geest/__init__.py @@ -28,7 +28,7 @@ #from .geest import Geest #from .core import RenderQueue, setting -from .core import setting, JSONValidator +from .core import setting #, JSONValidator from .utilities import resources_path from .gui import GeestOptionsFactory, GeestDock diff --git a/geest/gui/__init__.py b/geest/gui/__init__.py index 8c1d6192..cf21e39a 100644 --- a/geest/gui/__init__.py +++ b/geest/gui/__init__.py @@ -6,3 +6,5 @@ from .geest_dock import GeestDock from .geest_treeview import JsonTreeItem, JsonTreeModel, CustomTreeView from .setup_panel import SetupPanel +from .tree_panel import TreePanel +from .layer_detail_dialog import LayerDetailDialog diff --git a/geest/gui/geest_treeview.py b/geest/gui/geest_treeview.py index ff6cba59..c9d01f83 100644 --- a/geest/gui/geest_treeview.py +++ b/geest/gui/geest_treeview.py @@ -174,12 +174,19 @@ def setData(self, index, value, role=Qt.EditRole): def flags(self, index): """Allow editing of the name and weighting columns.""" + + #Override the flags method to allow specific columns to be editable. + + if not index.isValid(): + return Qt.NoItemFlags + item = index.internalPointer() - if index.column() == 0 or index.column() == 2: - # Allow editing for the first column (name) and third column (weighting) - return Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsEnabled - return Qt.ItemIsSelectable | Qt.ItemIsEnabled + # For example, only allow editing for the first and second columns + if index.column() == 0 or index.column() == 1: + return Qt.ItemIsEditable | Qt.ItemIsSelectable | Qt.ItemIsEnabled + return Qt.ItemIsSelectable | Qt.ItemIsEnabled + def update_font_color(self, item, color): """Update the font color of an item.""" item.font_color = color diff --git a/geest/gui/setup_panel.py b/geest/gui/setup_panel.py index 6c238025..583c1666 100644 --- a/geest/gui/setup_panel.py +++ b/geest/gui/setup_panel.py @@ -29,7 +29,7 @@ ) from qgis.PyQt.QtCore import QFileInfo, QSettings, QVariant from qgis.PyQt.QtGui import QPixmap -from ..utilities import resources_path +from geest.utilities import resources_path class SetupPanel(QWidget): diff --git a/geest/gui/tree_panel.py b/geest/gui/tree_panel.py index 6b82edaf..b89d8bdf 100644 --- a/geest/gui/tree_panel.py +++ b/geest/gui/tree_panel.py @@ -19,10 +19,10 @@ from qgis.PyQt.QtGui import QMovie import json import os -from .geest_treeview import CustomTreeView, JsonTreeModel -from .setup_panel import SetupPanel -from .layer_detail_dialog import LayerDetailDialog -from ..utilities import resources_path +from geest.gui import CustomTreeView, JsonTreeModel +from geest.gui import SetupPanel +from geest.gui import LayerDetailDialog +from geest.utilities import resources_path from geest.core import set_setting, setting class TreePanel(QWidget): @@ -115,6 +115,22 @@ def __init__(self, parent=None, json_file=None): button_bar.addWidget(self.edit_toggle) # Add the edit toggle layout.addLayout(button_bar) self.setLayout(layout) + + def edit(self, index, trigger, event): + """ + Override the edit method to enable editing only on the column that was clicked. + """ + # Get the column that was clicked + column = index.column() + + # Only allow editing on specific columns (e.g., column 0, 1, etc.) + if column == 0: # Only make the first column editable + return super().edit(index, trigger, event) + elif column == 2: # And the third column editable + return super().edit(index, trigger, event) + + # Return False if the column shouldn't be editable + return False def load_json(self): """Load the JSON data from the file.""" diff --git a/geest/geest2.ods b/geest/resources/geest2.ods similarity index 100% rename from geest/geest2.ods rename to geest/resources/geest2.ods diff --git a/geest/resources/model.json b/geest/resources/model.json index fb542a9d..15811b28 100644 --- a/geest/resources/model.json +++ b/geest/resources/model.json @@ -1,13 +1,13 @@ { "dimensions": [ { - "name": "CONTEXTUAL", + "name": "Contextual", "factors": [ { "name": "Workplace Discrimination", "layers": [ { - "layer": "WBL 2024 Workplace Index Score", + "Layer": "WBL 2024 Workplace Index Score", "Text": "Women, Business and the Law", "Default Weighting": 0.33, "Use Aggregate": 1.0, @@ -26,10 +26,14 @@ "Default Measurement": "", "Default Increments": "0,0,0", "Use Mode of Travel": 0.0, - "source": "Women, Business and the Law", - "indicator": "This value represents data at the national level and must be standardized on a scale ranging from 0 to 5. This indicator is composed by the Workplace Index score of the WBL 2024. The data is already formatted on scale from 1 to 100.", - "query": "WBL 2024 index score: 83.8" + "Source": "Women, Business and the Law", + "Indicator": "This value represents data at the national level and must be standardized on a scale ranging from 0 to 5. This indicator is composed by the Workplace Index score of the WBL 2024. The data is already formatted on scale from 1 to 100.", + "Query": "WBL 2024 index score: 83.8" } + ], + "weighting": 0.33, + "required_layers": [ + "workplace_score" ] }, { @@ -90,10 +94,14 @@ } ] } + ], + "weighting": 0.33, + "required_factors": [ + "workplace_discrimination" ] }, { - "name": "ACCESSIBILITY", + "name": "Accessibility", "factors": [ { "name": "Women's Travel Patterns", @@ -310,10 +318,10 @@ { "name": "Access to Financial Facilities", "layers": [ - { - "layer": "Location of Banks and other FF (OSM)", + { + "ID": "bank_locations", + "Layer": "Location of Banks and other FF (OSM)", "Text": "OSM", - "Default Weighting": 0.2, "Use Aggregate": 1.0, "Default Index Score": 0.0, "Index Score": 0, @@ -323,8 +331,8 @@ "Rasterise Polyline": 0.0, "Rasterise Point": 0, "Default Buffer Distances": "250, 500, 750, 1000, 1250", - "Use Buffer point": 1, - "Default pixel": 0, + "Use Buffer Point": 1, + "Default Pixel": 0, "Use Create Grid": 0, "Default Mode": "Walking", "Default Measurement": "Disctance", From df72f971c8c18abee8ab6f549437c5accc296a28 Mon Sep 17 00:00:00 2001 From: Tim Sutton Date: Mon, 16 Sep 2024 12:35:48 +0100 Subject: [PATCH 2/3] Fix imports --- export.json | 946 +++++++++++++++++++++++++++++++++++++ geest/core/__init__.py | 9 +- geest/gui/geest_dock.py | 2 +- geest/gui/tree_panel.py | 6 +- geest/resources/model.json | 30 +- 5 files changed, 962 insertions(+), 31 deletions(-) create mode 100644 export.json diff --git a/export.json b/export.json new file mode 100644 index 00000000..692617d2 --- /dev/null +++ b/export.json @@ -0,0 +1,946 @@ +{ + "dimensions": [ + { + "name": "contextual", + "factors": [ + { + "name": "Workplace Discrimination", + "layers": [ + { + "layer": "WBL 2024 Workplace Index Score", + "Text": "Women, Business and the Law", + "Default Weighting": 0.33, + "Use Aggregate": true, + "Default Index Score": 83.8, + "Index Score": 99, + "Use default Idex Score": true, + "Rasterise Raster": true, + "Rasterise Polygon": true, + "Rasterise Polyline": true, + "Rasterise Point": true, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": true, + "Default pixel": 0, + "Use Create Grid": false, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": false, + "source": "Women, Business and the Law", + "indicator": "This value represents data at the national level and must be standardized on a scale ranging from 0 to 5. This indicator is composed by the Workplace Index score of the WBL 2024. The data is already formatted on scale from 1 to 100. Test", + "query": "WBL 2024 index score: 83.8" + } + ] + }, + { + "name": "Regulatory Frameworks", + "layers": [ + { + "layer": "WBL 2024 Pay+Parenthood Index Score", + "Text": "Women, Business and the Law", + "Default Weighting": 0.33, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 100, + "Use default Idex Score": 1, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "Women, Business and the Law", + "indicator": "This value represents data at the national level and must be standardized on a scale ranging from 0 to 5. This indicator is composed by aggregating the Parenthood and Pay Index scores of the WBL 2024. The data is already formatted on scale from 1 to 100.", + "query": "WBL 2024 Pay (100)+Parenthood(40) Index Score" + } + ] + }, + { + "name": "Financial Inclusion", + "layers": [ + { + "layer": "WBL 2024 Entrepeneurship Index Score", + "Text": "Women, Business and the Law", + "Default Weighting": 0.33, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 100, + "Use default Idex Score": 1, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "Women, Business and the Law", + "indicator": "This value represents data at the national level and must be standardized on a scale ranging from 0 to 5. The data is already formatted on scale from 1 to 100. It comes from the Entrepeneurship rating of the 2024 WBL Index. ", + "query": "WBL 2024 Entrepeneurship Index Score: 75" + } + ] + } + ] + }, + { + "name": "accessibility", + "factors": [ + { + "name": "Women's Travel Patterns", + "layers": [ + { + "layer": "Location of kindergartens/childcare", + "Text": "OSM, Humdata", + "Default Weighting": 0.2, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "250, 500, 750, 1000, 1250", + "Use Buffer point": 1, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "Walking", + "Default Measurement": "Disctance", + "Default Increments": "250, 500, 750, 1000, 1250", + "Use Mode of Travel": 1.0, + "source": "OSM, Humdata", + "indicator": "This factor is assessed through network analyses to calculate catchment areas using Open Route Service. After each analysis, the territory is divided into 100m x 100m rasters, and the factor score is calculated as the average score within each raster. The scoring for each type of facility is categorized by distance as follows:0 to 400 meters: 5401 to 800 meters: 4801 to 1200 meters: 31201 to 1500 meters: 21501 to 2000 meters: 1Over 2000 meters: 0", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"amenity\"=\"kindergarten\"](area.area_0); way[\"amenity\"=\"kindergarten\"](area.area_0); relation[\"amenity\"=\"kindergarten\"](area.area_0););(._;>;);out body;" + }, + { + "layer": "Location of primary schools ", + "Text": "OSM, Humdata", + "Default Weighting": "", + "Use Aggregate": "", + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "250, 500, 750, 1000, 1250", + "Use Buffer point": 1, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "", + "Use Mode of Travel": "", + "source": "OSM, Humdata", + "indicator": "", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"amenity\"=\"school\"](area.area_0); way[\"amenity\"=\"school\"](area.area_0); relation[\"amenity\"=\"school\"](area.area_0););(._;>;);out body;" + }, + { + "layer": "Location of groceries", + "Text": "OSM", + "Default Weighting": "", + "Use Aggregate": "", + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "250, 500, 750, 1000, 1250", + "Use Buffer point": 1, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "", + "Use Mode of Travel": "", + "source": "OSM", + "indicator": "", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"shop\"=\"greengrocer\"](area.area_0); way[\"shop\"=\"greengrocer\"](area.area_0); relation[\"shop\"=\"greengrocer\"](area.area_0););(._;>;);out body;" + }, + { + "layer": "Location of pharmacies", + "Text": "OSM, NDVI", + "Default Weighting": "", + "Use Aggregate": "", + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "250, 500, 750, 1000, 1250", + "Use Buffer point": 1, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "", + "Use Mode of Travel": "", + "source": "OSM, NDVI", + "indicator": "", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"amenity\"=\"pharmacy\"](area.area_0); way[\"amenity\"=\"pharmacy\"](area.area_0); relation[\"amenity\"=\"pharmacy\"](area.area_0); );(._;>;);out body;" + }, + { + "layer": "Location of green spaces ", + "Text": "", + "Default Weighting": "", + "Use Aggregate": "", + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "250, 500, 750, 1000, 1250", + "Use Buffer point": 1, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "", + "Use Mode of Travel": "", + "source": "", + "indicator": "", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"leisure\"=\"park\"](area.area_0); node[\"boundary\"=\"national_park\"](area.area_0); way[\"leisure\"=\"park\"](area.area_0); way[\"boundary\"=\"national_park\"](area.area_0); relation[\"leisure\"=\"park\"](area.area_0); relation[\"boundary\"=\"national_park\"](area.area_0););(._;>;);out body;" + } + ] + }, + { + "name": "Access to Public Transport", + "layers": [ + { + "layer": "Location of public transportation stops, including maritime (OSM)", + "Text": "OSM", + "Default Weighting": 0.2, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "250, 500, 750, 1000, 1250", + "Use Buffer point": 1, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "Walking", + "Default Measurement": "Disctance", + "Default Increments": "250, 500, 750, 1000, 1250", + "Use Mode of Travel": 1.0, + "source": "OSM", + "indicator": "This factor is evaluated using the same methodology as for women's travel patterns, but with public transport stops as the points of interest. Additionally, the suggested thresholds should be adjusted to:0 to 250 meters: 5251 to 500 meters: 4501 to 750 meters: 3751 to 1,000 meters: 21,001 to 1,250 meters: 1Over 1,250 meters: 0", + "query": "\"[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"\"public_transport\"\"=\"\"stop_position\"\"](area.area_0); node[\"\"public_transport\"\"=\"\"platform\"\"](area.area_0); node[\"\"public_transport\"\"=\"\"station\"\"](area.area_0); node[\"\"public_transport\"\"=\"\"stop_area\"\"](area.area_0); node[\"\"highway\"\"=\"\"bus_stop\"\"](area.area_0); node[\"\"highway\"\"=\"\"platform\"\"](area.area_0); way[\"\"public_transport\"\"=\"\"stop_position\"\"](area.area_0); way[\"\"public_transport\"\"=\"\"platform\"\"](area.area_0); way[\"\"public_transport\"\"=\"\"station\"\"](area.area_0); way[\"\"public_transport\"\"=\"\"stop_area\"\"](area.area_0); way[\"\"highway\"\"=\"\"bus_stop\"\"](area.area_0); way[\"\"highway\"\"=\"\"platform\"\"](area.area_0); relation[\"\"public_transport\"\"=\"\"stop_position\"\"](area.area_0); relation[\"\"public_transport\"\"=\"\"platform\"\"](area.area_0); relation[\"\"public_transport\"\"=\"\"station\"\"](area.area_0); relation[\"\"public_transport\"\"=\"\"stop_area\"\"](area.area_0); relation[\"\"highway\"\"=\"\"bus_stop\"\"](area.area_0); relation[\"\"highway\"\"=\"\"platform\"\"](area.area_0); node[\"amenity\"=\"ferry_terminal\"](area.area_0); way[\"amenity\"=\"ferry_terminal\"](area.area_0); relation[\"amenity\"=\"ferry_terminal\"](area.area_0);););(._;>;);out body;\"" + } + ] + }, + { + "name": "Access to Health Facilities", + "layers": [ + { + "layer": "Location of hospitals and clinics (OSM)", + "Text": "OSM", + "Default Weighting": 0.2, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "250, 500, 750, 1000, 1250", + "Use Buffer point": 1, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "Walking", + "Default Measurement": "Disctance", + "Default Increments": "250, 500, 750, 1000, 1250", + "Use Mode of Travel": 1.0, + "source": "OSM", + "indicator": "The methodology is the same as for all Accessibility factors, but using hospitals and clinics as the points of interest. This time, the suggested thresholds should be adjusted to:0 to 1,000 meters: 51,001 to 2,000 meters: 42,001 to 3,000 meters: 33,001 to 4,000 meters: 24,001 to 5,000 meters: 1Over 5,000 meters: 0", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"amenity\"=\"dentist\"](area.area_0); node[\"amenity\"=\"doctors\"](area.area_0); node[\"amenity\"=\"hospital\"](area.area_0); node[\"amenity\"=\"pharmacy\"](area.area_0); node[\"amenity\"=\"clinic\"](area.area_0); way[\"amenity\"=\"dentist\"](area.area_0); way[\"amenity\"=\"doctors\"](area.area_0); way[\"amenity\"=\"hospital\"](area.area_0); way[\"amenity\"=\"pharmacy\"](area.area_0); way[\"amenity\"=\"clinic\"](area.area_0); relation[\"amenity\"=\"dentist\"](area.area_0); relation[\"amenity\"=\"doctors\"](area.area_0); relation[\"amenity\"=\"hospital\"](area.area_0); relation[\"amenity\"=\"pharmacy\"](area.area_0); relation[\"amenity\"=\"clinic\"](area.area_0););(._;>;);out body;" + } + ] + }, + { + "name": "Access to Education and Training Facilities", + "layers": [ + { + "layer": "Location of universities and technical schools (OSM, Hummanitarian Data Exchange)", + "Text": "OSM, Humdata", + "Default Weighting": 0.2, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "250, 500, 750, 1000, 1250", + "Use Buffer point": 1, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "Walking", + "Default Measurement": "Disctance", + "Default Increments": "250, 500, 750, 1000, 1250", + "Use Mode of Travel": 1.0, + "source": "OSM, Humdata", + "indicator": "The methodology is the same as for all Accessibility factors, but using universities and trainning facilities as the points of interest. This time, the suggested thresholds should be adjusted to:0 to 2,000 meters: 52,001 to 4,000 meters: 44,001 to 6,000 meters: 36,001 to 8,000 meters: 28,001 to 10,000 meters: 1Over 10,000 meters: 0", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"amenity\"=\"university\"](area.area_0); way[\"amenity\"=\"university\"](area.area_0); relation[\"amenity\"=\"university\"](area.area_0););(._;>;);out body;" + } + ] + }, + { + "name": "Access to Financial Facilities", + "layers": [ + { + "layer": "Location of Banks and other FF (OSM)", + "Text": "OSM", + "Default Weighting": 0.2, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "250, 500, 750, 1000, 1250", + "Use Buffer point": 1, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "Walking", + "Default Measurement": "Disctance", + "Default Increments": "250, 500, 750, 1000, 1250", + "Use Mode of Travel": 1.0, + "source": "OSM", + "indicator": "The methodology is the same as for all Accessibility factors, but using financial facilities (except for ATMs) as the points of interest. This time, the suggested thresholds should be adjusted to:0 to 400 meters: 5401 to 800 meters: 4801 to 1,200 meters: 31,201 to 2,000 meters: 22,001 to 3,000 meters: 1Over 3,000 meters: 0", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"amenity\"=\"bank\"](area.area_0); node[\"office\"=\"financial\"](area.area_0); way[\"amenity\"=\"bank\"](area.area_0); way[\"office\"=\"financial\"](area.area_0); relation[\"amenity\"=\"bank\"](area.area_0); relation[\"office\"=\"financial\"](area.area_0););(._;>;);out body;" + } + ] + } + ] + }, + { + "name": "place characterization", + "factors": [ + { + "name": "Active Transport", + "layers": [ + { + "layer": "Location of street crossings", + "Text": "OSM", + "Default Weighting": 0.14, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "OSM", + "indicator": "This indicator is composed by calculating the average of these four factors. First, the territory needs to be divided into 100m x 100m rasters.1. Street Crossings (indicates safety and accessibility; measured by availability/presence per raster cell)\u20220: No crossings\u20223: 1 crossing \u20225: 2 or more crossings2. Cycle Paths (measured by availability/presence per raster)\u20220: No cycle paths\u20223: 1 cycle path \u20225: 2 or more cycle paths3. Footpaths (measured by availability/presence per raster)\u20220: No footpaths\u20223: 1 footpath \u20225: 2 or more footpaths4. Block Sizes(indicates encouraged walkability)\u20221: Very large block sizes (>1 km)\u20222: Large block sizes (751m - 1 km)\u20223: Moderate block sizes (501m - 750m)\u20224: Small block sizes (251m - 500m)\u20225: Very small block sizes (<250m)", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"highway\"=\"crossing\"](area.area_0); node[\"railway\"=\"crossing\"](area.area_0); way[\"highway\"=\"crossing\"](area.area_0); way[\"railway\"=\"crossing\"](area.area_0); relation[\"highway\"=\"crossing\"](area.area_0); relation[\"railway\"=\"crossing\"](area.area_0););(._;>;);out body;" + }, + { + "layer": NaN, + "Text": "Mapillary", + "Default Weighting": "", + "Use Aggregate": "", + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "Mapillary", + "indicator": "", + "query": "endpoints: construction--flat--crosswalk-plain and marking--discrete--crosswalk-zebra" + }, + { + "layer": "Location of cycle paths (OSM)", + "Text": "OSM", + "Default Weighting": "", + "Use Aggregate": "", + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "OSM", + "indicator": "", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"highway\"=\"cycleway\"](area.area_0); node[\"highway\"=\"track\"](area.area_0); node[\"cycleway\"=\"track\"](area.area_0); node[\"cycleway\"=\"lane\"](area.area_0); node[\"cycleway\"=\"share_busway\"](area.area_0); node[\"cycleway\"=\"shared_lane\"](area.area_0); way[\"highway\"=\"cycleway\"](area.area_0); way[\"highway\"=\"track\"](area.area_0); way[\"cycleway\"=\"track\"](area.area_0); way[\"cycleway\"=\"lane\"](area.area_0); way[\"cycleway\"=\"share_busway\"](area.area_0); way[\"cycleway\"=\"shared_lane\"](area.area_0); relation[\"highway\"=\"cycleway\"](area.area_0); relation[\"highway\"=\"track\"](area.area_0); relation[\"cycleway\"=\"track\"](area.area_0); relation[\"cycleway\"=\"lane\"](area.area_0); relation[\"cycleway\"=\"share_busway\"](area.area_0); relation[\"cycleway\"=\"shared_lane\"](area.area_0););(._;>;);out body;" + }, + { + "layer": "Location of footpaths (OSM)", + "Text": "OSM", + "Default Weighting": "", + "Use Aggregate": "", + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "OSM", + "indicator": "", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"highway\"=\"footway\"](area.area_0); way[\"highway\"=\"footway\"](area.area_0); relation[\"highway\"=\"footway\"](area.area_0););(._;>;);out body;" + }, + { + "layer": "Block Layout (OSM)", + "Text": "OSM", + "Default Weighting": "", + "Use Aggregate": "", + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "OSM", + "indicator": "", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"landuse\"=\"residential\"](area.area_0); node[\"landuse\"=\"commercial\"](area.area_0); node[\"landuse\"=\"industrial\"](area.area_0); node[\"boundary\"=\"administrative\"](area.area_0); way[\"landuse\"=\"residential\"](area.area_0); way[\"landuse\"=\"commercial\"](area.area_0); way[\"landuse\"=\"industrial\"](area.area_0); way[\"boundary\"=\"administrative\"](area.area_0); relation[\"landuse\"=\"residential\"](area.area_0); relation[\"landuse\"=\"commercial\"](area.area_0); relation[\"landuse\"=\"industrial\"](area.area_0); relation[\"boundary\"=\"administrative\"](area.area_0););(._;>;);out body;" + } + ] + }, + { + "name": "Safety", + "layers": [ + { + "layer": "Street lights/Nigthttime ligths", + "Text": "Mapillary", + "Default Weighting": 0.14, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 100, + "Use default Idex Score": 1, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "Mapillary", + "indicator": "This indicator should be calculated by creating 20-meter buffers around streetlights. Raster cells in which 80-100% of their area intersects with the buffers should receive a score of 5. Rasters with 60-79% intersection should be scored as 4, 40-59% as 3, 20-39% as 2, and 1-19% as 1. Areas without any overlap with streetlight buffers should be scored as 0. NOTE: Use nighttime lights only if street lights are absent/ If no spatial features are available, the user should have the option to use disaggregated statistics on crime rates or perceptions of safety as input.", + "query": "endpoint: object--street-light" + }, + { + "layer": NaN, + "Text": "Nightime lights", + "Default Weighting": "", + "Use Aggregate": "", + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "Nightime lights", + "indicator": "", + "query": "" + } + ] + }, + { + "name": "FCV", + "layers": [ + { + "layer": "ACLED data (Violence Estimated Events)", + "Text": "ACLED", + "Default Weighting": 0.14, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "check (input radius)", + "Use Buffer point": 1, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "ACLED", + "indicator": "This indicator should be structured by assigning scores to rasters based on their overlap with buffers indicating different types of events. Using point locations of FCV events, generate circular buffers with a radius of 5 km to estimate the spatial impact of these events. If the impact radius of an event is known, it should be used instead. Any raster intersecting with the buffer should be scored as follows:\u2022Rasters overlapping with buffers indicating battles and explosions: score 0\u2022Rasters overlapping with buffers indicating explosions and remote violence: score 1\u2022Rasters overlapping with buffers indicating violence against civilians: score 2\u2022Rasters overlapping with buffers indicating protests and riots: score 4\u2022Areas that do not overlap with any event: score 5", + "query": "" + } + ] + }, + { + "name": "Education", + "layers": [ + { + "layer": "percentage of the labor force comprising women with university degrees ", + "Text": " Central Statistics Office/Humdata", + "Default Weighting": 0.14, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 100, + "Use default Idex Score": 1, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": " Central Statistics Office/Humdata", + "indicator": "Reclassify the input data to a standardized scale from 0 to 5 using a linear scaling process. In this scale, a score of 5 represents areas where all women have a university degree, while a score of 0 represents areas where no women have a university degree. Users should have the option to upload disaggregated data at various administrative levels or at the country level.", + "query": "" + } + ] + }, + { + "name": "Digital Inclusion", + "layers": [ + { + "layer": "Individuals using the Internet (% of population)", + "Text": "World Bank", + "Default Weighting": 0.14, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 100, + "Use default Idex Score": 1, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "World Bank", + "indicator": "Reclassify input data to a standardized scale of 0 to 5 using a linear scaling process, such that 5 represents areas where 100% of houses have Internet access, and 0 represents areas where no houses have Internet access. Users should have the option to upload disaggregated data at various administrative levels or at the country level.", + "query": "" + } + ] + }, + { + "name": "Environmental Hazards", + "layers": [ + { + "layer": "Global Natural Hazards Data", + "Text": "National Centers for Environmental Information", + "Default Weighting": 0.14, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "National Centers for Environmental Information", + "indicator": "Reclassify input data to a standardized scale of 0 to 5 using a linear scaling process, such that 5 represents areas where there are no environmental hazards and 0 represents the areas with the highest level of hazard.", + "query": "" + } + ] + }, + { + "name": "Water sanitation", + "layers": [ + { + "layer": "Water points (OSM), catch basins, water valves and fire hydrants (Mapillary) ", + "Text": "OSM", + "Default Weighting": 0.14, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": 1000, + "Use Buffer point": 1, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "OSM", + "indicator": "This indicator is composed by assessing the presence of any of these four factors in a raster cell. First, the territory needs to be divided into 100m x 100m rasters. The scoring for each cell is as follows:Raster cell with no water points: score 0Raster cell with 1 water point: score 3Raster cell with 2 or more water points: score 5", + "query": "[out:xml] [timeout:25]; {{geocodeArea:Saint Lucia}} -> .area_0;( node[\"emergency\"=\"fire_hydrant\"](area.area_0); node[\"emergency\"=\"water_tank\"](area.area_0); node[\"amenity\"=\"drinking_water\"](area.area_0); node[\"amenity\"=\"water_point\"](area.area_0); way[\"emergency\"=\"fire_hydrant\"](area.area_0); way[\"emergency\"=\"water_tank\"](area.area_0); way[\"amenity\"=\"drinking_water\"](area.area_0); way[\"amenity\"=\"water_point\"](area.area_0); relation[\"emergency\"=\"fire_hydrant\"](area.area_0); relation[\"emergency\"=\"water_tank\"](area.area_0); relation[\"amenity\"=\"drinking_water\"](area.area_0); relation[\"amenity\"=\"water_point\"](area.area_0););(._;>;);out body;" + }, + { + "layer": NaN, + "Text": "Mapillary", + "Default Weighting": "", + "Use Aggregate": "", + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": "", + "Rasterise Polygon": 0, + "Rasterise Polyline": "", + "Rasterise Point": 0, + "Default Buffer Distances": 1000, + "Use Buffer point": 1, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": "", + "source": "Mapillary", + "indicator": "", + "query": "endpoints: object--catch-basin object--water-valve and object--fire-hydrant" + } + ] + } + ] + }, + { + "name": "about ", + "factors": [ + { + "name": "Water sanitation", + "layers": [ + { + "layer": NaN, + "Text": "", + "Default Weighting": 0.0, + "Use Aggregate": 0.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "", + "indicator": "", + "query": "" + } + ] + } + ] + }, + { + "name": "setup", + "factors": [ + { + "name": "Water sanitation", + "layers": [ + { + "layer": NaN, + "Text": "", + "Default Weighting": 0.0, + "Use Aggregate": 0.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 100, + "Use Create Grid": 1, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "", + "indicator": "", + "query": "" + } + ] + } + ] + }, + { + "name": "aggregate", + "factors": [ + { + "name": "Contextual", + "layers": [ + { + "layer": "Contectual Score", + "Text": "", + "Default Weighting": 0.33, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "", + "indicator": "", + "query": "" + } + ] + }, + { + "name": "Accessibility", + "layers": [ + { + "layer": "Accessibility Score", + "Text": "", + "Default Weighting": 0.33, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "", + "indicator": "", + "query": "" + } + ] + }, + { + "name": "Place Characherisation", + "layers": [ + { + "layer": "Place Score", + "Text": "", + "Default Weighting": 0.33, + "Use Aggregate": 1.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "", + "indicator": "", + "query": "" + } + ] + } + ] + }, + { + "name": "insignts", + "factors": [ + { + "name": "Enablement", + "layers": [ + { + "layer": NaN, + "Text": "", + "Default Weighting": 0.0, + "Use Aggregate": 0.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "", + "indicator": "", + "query": "" + } + ] + }, + { + "name": "Re Zone Raster Locations", + "layers": [ + { + "layer": NaN, + "Text": "", + "Default Weighting": 0.0, + "Use Aggregate": 0.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "", + "indicator": "", + "query": "" + } + ] + }, + { + "name": "Re Point Locations", + "layers": [ + { + "layer": NaN, + "Text": "", + "Default Weighting": 0.0, + "Use Aggregate": 0.0, + "Default Index Score": 0.0, + "Index Score": 0, + "Use default Idex Score": 0, + "Rasterise Raster": 0.0, + "Rasterise Polygon": 0, + "Rasterise Polyline": 0.0, + "Rasterise Point": 0, + "Default Buffer Distances": "0,0,0", + "Use Buffer point": 0, + "Default pixel": 0, + "Use Create Grid": 0, + "Default Mode": "", + "Default Measurement": "", + "Default Increments": "0,0,0", + "Use Mode of Travel": 0.0, + "source": "", + "indicator": "", + "query": "" + } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/geest/core/__init__.py b/geest/core/__init__.py index b20d6f9c..e92c4776 100644 --- a/geest/core/__init__.py +++ b/geest/core/__init__.py @@ -5,12 +5,5 @@ from .constants import APPLICATION_NAME from .settings import setting, set_setting -#from .animation_controller import ( -# MapMode, -# AnimationController, -# InvalidAnimationParametersException, -#) from .default_settings import default_settings -from .json_validator import JSONValidator -#from .movie_creator import MovieFormat, MovieCommandGenerator, MovieCreationTask -#from .render_queue import RenderJob, RenderQueue +#from .json_validator import JSONValidator diff --git a/geest/gui/geest_dock.py b/geest/gui/geest_dock.py index 42483cf3..d1f33a76 100644 --- a/geest/gui/geest_dock.py +++ b/geest/gui/geest_dock.py @@ -23,7 +23,7 @@ from .setup_panel import SetupPanel from .tree_panel import TreePanel from .layer_detail_dialog import LayerDetailDialog -from ..utilities import resources_path +from geest.utilities import resources_path class GeestDock(QDockWidget): diff --git a/geest/gui/tree_panel.py b/geest/gui/tree_panel.py index b89d8bdf..5c2fbd0a 100644 --- a/geest/gui/tree_panel.py +++ b/geest/gui/tree_panel.py @@ -19,9 +19,9 @@ from qgis.PyQt.QtGui import QMovie import json import os -from geest.gui import CustomTreeView, JsonTreeModel -from geest.gui import SetupPanel -from geest.gui import LayerDetailDialog +from .geest_treeview import CustomTreeView, JsonTreeModel +from .setup_panel import SetupPanel +from .layer_detail_dialog import LayerDetailDialog from geest.utilities import resources_path from geest.core import set_setting, setting diff --git a/geest/resources/model.json b/geest/resources/model.json index 15811b28..fb542a9d 100644 --- a/geest/resources/model.json +++ b/geest/resources/model.json @@ -1,13 +1,13 @@ { "dimensions": [ { - "name": "Contextual", + "name": "CONTEXTUAL", "factors": [ { "name": "Workplace Discrimination", "layers": [ { - "Layer": "WBL 2024 Workplace Index Score", + "layer": "WBL 2024 Workplace Index Score", "Text": "Women, Business and the Law", "Default Weighting": 0.33, "Use Aggregate": 1.0, @@ -26,14 +26,10 @@ "Default Measurement": "", "Default Increments": "0,0,0", "Use Mode of Travel": 0.0, - "Source": "Women, Business and the Law", - "Indicator": "This value represents data at the national level and must be standardized on a scale ranging from 0 to 5. This indicator is composed by the Workplace Index score of the WBL 2024. The data is already formatted on scale from 1 to 100.", - "Query": "WBL 2024 index score: 83.8" + "source": "Women, Business and the Law", + "indicator": "This value represents data at the national level and must be standardized on a scale ranging from 0 to 5. This indicator is composed by the Workplace Index score of the WBL 2024. The data is already formatted on scale from 1 to 100.", + "query": "WBL 2024 index score: 83.8" } - ], - "weighting": 0.33, - "required_layers": [ - "workplace_score" ] }, { @@ -94,14 +90,10 @@ } ] } - ], - "weighting": 0.33, - "required_factors": [ - "workplace_discrimination" ] }, { - "name": "Accessibility", + "name": "ACCESSIBILITY", "factors": [ { "name": "Women's Travel Patterns", @@ -318,10 +310,10 @@ { "name": "Access to Financial Facilities", "layers": [ - { - "ID": "bank_locations", - "Layer": "Location of Banks and other FF (OSM)", + { + "layer": "Location of Banks and other FF (OSM)", "Text": "OSM", + "Default Weighting": 0.2, "Use Aggregate": 1.0, "Default Index Score": 0.0, "Index Score": 0, @@ -331,8 +323,8 @@ "Rasterise Polyline": 0.0, "Rasterise Point": 0, "Default Buffer Distances": "250, 500, 750, 1000, 1250", - "Use Buffer Point": 1, - "Default Pixel": 0, + "Use Buffer point": 1, + "Default pixel": 0, "Use Create Grid": 0, "Default Mode": "Walking", "Default Measurement": "Disctance", From 3dcbaf39fcb634262eb47498253cd5c6e3edbbcd Mon Sep 17 00:00:00 2001 From: hennie Date: Mon, 16 Sep 2024 15:56:46 +0200 Subject: [PATCH 3/3] Introduces initial implementations of the base_dialog and widget_factory --- .gitignore | 1 + geest/gui/dialogs/__init__.py | 5 ++ geest/gui/dialogs/base_dialog.py | 88 ++++++++++++++++++++++ geest/gui/dialogs/index_score_dialog.py | 28 +++++++ geest/gui/dialogs/osm_downloader_dialog.py | 26 +++++++ geest/gui/widgets/__init__.py | 3 + geest/gui/widgets/widget_factory.py | 77 +++++++++++++++++++ 7 files changed, 228 insertions(+) create mode 100644 geest/gui/dialogs/__init__.py create mode 100644 geest/gui/dialogs/base_dialog.py create mode 100644 geest/gui/dialogs/index_score_dialog.py create mode 100644 geest/gui/dialogs/osm_downloader_dialog.py create mode 100644 geest/gui/widgets/__init__.py create mode 100644 geest/gui/widgets/widget_factory.py diff --git a/.gitignore b/.gitignore index c1420e28..8c407378 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,4 @@ nix-result/ data core app.py +/geest.zip diff --git a/geest/gui/dialogs/__init__.py b/geest/gui/dialogs/__init__.py new file mode 100644 index 00000000..2e49511c --- /dev/null +++ b/geest/gui/dialogs/__init__.py @@ -0,0 +1,5 @@ +from .base_dialog import BaseDialog +from .osm_downloader_dialog import OSMDownloaderDialog +from .index_score_dialog import IndexScoreDialog + +__all__ = ['BaseDialog', 'OSMDownloaderDialog', 'IndexScoreDialog'] diff --git a/geest/gui/dialogs/base_dialog.py b/geest/gui/dialogs/base_dialog.py new file mode 100644 index 00000000..4ad6eeb3 --- /dev/null +++ b/geest/gui/dialogs/base_dialog.py @@ -0,0 +1,88 @@ +from abc import ABC, abstractmethod +from qgis.PyQt.QtWidgets import QDialog, QVBoxLayout, QLabel, QHBoxLayout, QPushButton +from qgis.PyQt.QtCore import Qt + +from GEEST2.geest.gui.widgets.widget_factory import WidgetFactory + + +class BaseDialog(QDialog, ABC): + def __init__(self, input_specs: dict, on_accept_callback, parent=None): + """ + Initialize the base dialog. + + :param input_specs: Dictionary containing dialog specifications. + :param on_accept_callback: Callback function to handle inputs upon acceptance. + :param parent: Parent widget. + """ + super().__init__(parent) + self.input_specs = input_specs + self.widgets = {} + self.on_accept_callback = on_accept_callback + self.init_ui() + + def init_ui(self): + # Set dialog properties + self.setWindowTitle(self.input_specs.get('title', 'Dialog')) + self.layout = QVBoxLayout() + self.setLayout(self.layout) + + # Iterate over input specifications to create widgets + for element in self.input_specs.get('elements', []): + widget_type = element.get('type') + label_text = element.get('label', '') + widget = self.create_widget(widget_type, element) + + if label_text: + label = QLabel(label_text) + label.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) + self.layout.addWidget(label) + + if widget: + self.layout.addWidget(widget) + self.widgets[element.get('name')] = widget + + # Add dialog buttons + self.add_buttons() + + def add_buttons(self): + button_layout = QHBoxLayout() + self.ok_button = QPushButton("OK") + self.cancel_button = QPushButton("Cancel") + self.ok_button.clicked.connect(self.handle_accept) + self.cancel_button.clicked.connect(self.reject) + button_layout.addStretch() + button_layout.addWidget(self.ok_button) + button_layout.addWidget(self.cancel_button) + self.layout.addLayout(button_layout) + + def create_widget(self, widget_type, spec): + return WidgetFactory.create_widget(widget_type, spec, self) + + def get_inputs(self): + inputs = {} + for name, widget in self.widgets.items(): + spec = next((elem for elem in self.input_specs['elements'] if elem['name'] == name), None) + if spec: + inputs[name] = WidgetFactory.get_widget_value(widget, spec) + return inputs + + def handle_accept(self): + if self.validate_inputs(): + inputs = self.get_inputs() + self.on_accept_callback(inputs) + self.accept() + else: + # handle validation failure + pass + + @staticmethod + def validate_inputs(): + # input validation happens here + return True + + @abstractmethod + def process_inputs(self, inputs: dict): + """ + This must be implemented by derived classes! + """ + pass diff --git a/geest/gui/dialogs/index_score_dialog.py b/geest/gui/dialogs/index_score_dialog.py new file mode 100644 index 00000000..8346ff83 --- /dev/null +++ b/geest/gui/dialogs/index_score_dialog.py @@ -0,0 +1,28 @@ +from .base_dialog import BaseDialog + +class IndexScoreDialog(BaseDialog): + def __init__(self, on_accept_callback, parent=None): + input_specs = { + 'title': 'Index Score Configuration', + 'elements': [ + { + 'type': 'doublespinbox', + 'label': 'Default Value', + 'name': 'default_value', + 'min': 0.0, + 'max': 100.0, + 'decimals': 2, + 'default': 50.0 + }, + { + 'type': 'spinbox', + 'label': 'Allowed Range', + 'name': 'allowed_range', + 'min': 1, + 'max': 10, + 'default': 5 + }, + # other widgettes go here + ] + } + super().__init__(input_specs, on_accept_callback, parent) diff --git a/geest/gui/dialogs/osm_downloader_dialog.py b/geest/gui/dialogs/osm_downloader_dialog.py new file mode 100644 index 00000000..d8fefd93 --- /dev/null +++ b/geest/gui/dialogs/osm_downloader_dialog.py @@ -0,0 +1,26 @@ +from .base_dialog import BaseDialog + +class OSMDownloaderDialog(BaseDialog): + def __init__(self, on_accept_callback, parent=None): + input_specs = { + 'title': 'OSM Downloader', + 'elements': [ + { + 'type': 'radiobutton', + 'label': 'Data Source', + 'name': 'data_source', + 'options': [ + {'label': 'Manual Input', 'id': 'manual', 'checked': True}, + {'label': 'Download from OSM', 'id': 'osm'} + ] + }, + { + 'type': 'lineedit', + 'label': 'OSM Query', + 'name': 'osm_query', + 'default': 'highway=primary' + }, + # more weedjits here + ] + } + super().__init__(input_specs, on_accept_callback, parent) diff --git a/geest/gui/widgets/__init__.py b/geest/gui/widgets/__init__.py new file mode 100644 index 00000000..13256c5e --- /dev/null +++ b/geest/gui/widgets/__init__.py @@ -0,0 +1,3 @@ +from .widget_factory import WidgetFactory + +__all__ = ['WidgetFactory'] \ No newline at end of file diff --git a/geest/gui/widgets/widget_factory.py b/geest/gui/widgets/widget_factory.py new file mode 100644 index 00000000..a5ede6ba --- /dev/null +++ b/geest/gui/widgets/widget_factory.py @@ -0,0 +1,77 @@ +from qgis.PyQt.QtWidgets import ( + QDoubleSpinBox, QSpinBox, QLineEdit, QComboBox, QRadioButton, QButtonGroup, + QFileDialog, QWidget, QHBoxLayout +) +from qgis.gui import QgsLayerComboBox +from qgis.core import QgsMapLayer + +class WidgetFactory: + @staticmethod + def create_widget(widget_type, spec, parent): + if widget_type == 'doublespinbox': + widget = QDoubleSpinBox(parent) + widget.setRange(spec.get('min', -1e10), spec.get('max', 1e10)) + widget.setDecimals(spec.get('decimals', 2)) + widget.setValue(spec.get('default', 0.0)) + return widget + elif widget_type == 'spinbox': + widget = QSpinBox(parent) + widget.setRange(spec.get('min', -1e9), spec.get('max', 1e9)) + widget.setValue(spec.get('default', 0)) + return widget + elif widget_type == 'lineedit': + widget = QLineEdit(parent) + widget.setText(spec.get('default', '')) + return widget + elif widget_type == 'dropdown': + widget = QComboBox(parent) + options = spec.get('options', []) + widget.addItems(options) + default = spec.get('default') + if default in options: + widget.setCurrentText(default) + elif options: + widget.setCurrentText(options[0]) + return widget + elif widget_type == 'radiobutton': + button_group = QButtonGroup(parent) + layout = QHBoxLayout() + container = QWidget(parent) + container.setLayout(layout) + for option in spec.get('options', []): + rb = QRadioButton(option['label']) + rb.setChecked(option.get('checked', False)) + button_group.addButton(rb, id=option.get('id')) + layout.addWidget(rb) + container.button_group = button_group # Attach the button group for retrieval + return container + elif widget_type == 'layerselector': + widget = QgsLayerComboBox(parent) + layer_type = spec.get('layer_type', 'vector') # can be vector or raster + if layer_type == 'vector': + widget.setFilters(QgsMapLayer.VectorLayer) + elif layer_type == 'raster': + widget.setFilters(QgsMapLayer.RasterLayer) + widget.setCurrentLayer(spec.get('default_layer', None)) + return widget + # more widgets go here + else: + return None + + @staticmethod + def get_widget_value(widget, spec): + widget_type = spec.get('type') + if widget_type in ['doublespinbox', 'spinbox']: + return widget.value() + elif widget_type == 'lineedit': + return widget.text() + elif widget_type == 'dropdown': + return widget.currentText() + elif widget_type == 'radiobutton': + checked_button = widget.button_group.checkedButton() + return checked_button.text() if checked_button else None + elif widget_type == 'layerselector': + layer = widget.currentLayer() + return layer.name() if layer else None + else: + return None