From dc882ce8b9ca630d0eceeb830372d73b9ebd9be7 Mon Sep 17 00:00:00 2001 From: Tim Sutton Date: Tue, 17 Sep 2024 23:32:46 +0100 Subject: [PATCH 1/5] Tidy up layer dialog --- geest/gui/layer_detail_dialog.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/geest/gui/layer_detail_dialog.py b/geest/gui/layer_detail_dialog.py index eef7c7ed..eceb7397 100644 --- a/geest/gui/layer_detail_dialog.py +++ b/geest/gui/layer_detail_dialog.py @@ -41,10 +41,21 @@ def __init__(self, layer_name, layer_data, tree_item, editing=False, parent=None self.button_group = QButtonGroup() # To group radio buttons layout = QVBoxLayout() + # Make the dialog wider and add padding + self.resize(800, 600) # Set a wider dialog size + layout.setContentsMargins(20, 20, 20, 20) # Add padding around the layout + # Heading for the dialog heading_label = QLabel(layer_name) + heading_label.setStyleSheet("font-size: 18px; font-weight: bold;") # Bold heading layout.addWidget(heading_label) + # Line separator between heading and text edits + line = QFrame() + line.setFrameShape(QFrame.HLine) + line.setFrameShadow(QFrame.Sunken) + layout.addWidget(line) + # Create a horizontal splitter to hold both the Markdown editor and the preview splitter = QSplitter(Qt.Horizontal) @@ -55,9 +66,11 @@ def __init__(self, layer_name, layer_data, tree_item, editing=False, parent=None if self.editing: splitter.addWidget(self.text_edit_left) - # Create the QTextEdit for HTML preview (right side) + # Create the QTextEdit for HTML preview (right side, styled to look like a label) self.text_edit_right = QTextEdit() self.text_edit_right.setReadOnly(True) # Set as read-only for preview + self.text_edit_right.setFrameStyle(QFrame.NoFrame) # Remove the frame + self.text_edit_right.setStyleSheet("background-color: transparent;") # Match form background splitter.addWidget(self.text_edit_right) layout.addWidget(splitter) @@ -170,7 +183,6 @@ def add_config_widgets(self, layout): self.button_group.addButton(radio_button) # Add a label next to the radio button with the key's name - # Todo @hennie replace this with widget factory label = QLabel(key) frame_layout.addWidget(label) @@ -212,7 +224,7 @@ def get_updated_data_from_table(self): updated_data[key] = updated_value # Update the dictionary with the key-value pair # Include the Markdown text from the left text edit - # Special case so we need to write it last updated_data["Text"] = self.text_edit_left.toPlainText() return updated_data + From d4e4e284c161d48b0cbda4f5b10069f6a5fa8377 Mon Sep 17 00:00:00 2001 From: Tim Sutton Date: Tue, 17 Sep 2024 23:44:00 +0100 Subject: [PATCH 2/5] Tidy up layer dialog --- geest/gui/layer_detail_dialog.py | 50 ++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/geest/gui/layer_detail_dialog.py b/geest/gui/layer_detail_dialog.py index eceb7397..af3e5e92 100644 --- a/geest/gui/layer_detail_dialog.py +++ b/geest/gui/layer_detail_dialog.py @@ -19,6 +19,7 @@ QFrame, QRadioButton, QButtonGroup, + QDialogButtonBox ) from qgis.PyQt.QtCore import Qt, pyqtSignal from .toggle_switch import ToggleSwitch @@ -47,8 +48,12 @@ def __init__(self, layer_name, layer_data, tree_item, editing=False, parent=None # Heading for the dialog heading_label = QLabel(layer_name) - heading_label.setStyleSheet("font-size: 18px; font-weight: bold;") # Bold heading - layout.addWidget(heading_label) + heading_label.setStyleSheet( + "font-size: 18px; font-weight: bold;" + ) # Bold heading + layout.addWidget( + heading_label, alignment=Qt.AlignTop + ) # Align heading at the top # Line separator between heading and text edits line = QFrame() @@ -70,7 +75,9 @@ def __init__(self, layer_name, layer_data, tree_item, editing=False, parent=None self.text_edit_right = QTextEdit() self.text_edit_right.setReadOnly(True) # Set as read-only for preview self.text_edit_right.setFrameStyle(QFrame.NoFrame) # Remove the frame - self.text_edit_right.setStyleSheet("background-color: transparent;") # Match form background + self.text_edit_right.setStyleSheet( + "background-color: transparent;" + ) # Match form background splitter.addWidget(self.text_edit_right) layout.addWidget(splitter) @@ -98,10 +105,11 @@ def __init__(self, layer_name, layer_data, tree_item, editing=False, parent=None # Add the configuration frame with radio buttons self.add_config_widgets(layout) - # Close button - close_button = QPushButton("Close") - close_button.clicked.connect(self.on_close) # Connect close button to custom close handler - layout.addWidget(close_button) + # Create a QDialogButtonBox for OK/Cancel buttons + button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + button_box.accepted.connect(self.accept_changes) # Connect OK to accept_changes + button_box.rejected.connect(self.reject) # Connect Cancel to reject the dialog + layout.addWidget(button_box, alignment=Qt.AlignBottom) # Place at the bottom self.setLayout(layout) @@ -112,11 +120,13 @@ def populate_table(self): """Populate the table with all key-value pairs except 'indicator'.""" filtered_data = {k: v for k, v in self.layer_data.items() if k != "indicator"} self.table.setRowCount(len(filtered_data)) - + for row, (key, value) in enumerate(filtered_data.items()): # Column 1: Key (Property name, read-only) key_item = QTableWidgetItem(str(key)) - key_item.setFlags(key_item.flags() & ~Qt.ItemIsEditable) # Make it read-only + key_item.setFlags( + key_item.flags() & ~Qt.ItemIsEditable + ) # Make it read-only self.table.setItem(row, 0, key_item) # Column 2: Value (use appropriate widgets based on data type) @@ -167,7 +177,9 @@ def add_config_widgets(self, layout): frame_layout = QVBoxLayout() # Find all keys that start with 'Use' and have a value of True - use_keys = {k: v for k, v in self.layer_data.items() if k.startswith("Use") and v} + use_keys = { + k: v for k, v in self.layer_data.items() if k.startswith("Use") and v + } if use_keys: for i, key in enumerate(use_keys): @@ -189,8 +201,8 @@ def add_config_widgets(self, layout): frame.setLayout(frame_layout) layout.addWidget(frame) - def on_close(self): - """Handle the dialog close event by writing the edited data back to the TreeView item.""" + def accept_changes(self): + """Handle the OK button by applying changes and closing the dialog.""" updated_data = self.get_updated_data_from_table() # Set 'Analysis Mode' based on the selected radio button @@ -199,7 +211,7 @@ def on_close(self): updated_data["Analysis Mode"] = selected_button.text() self.dataUpdated.emit(updated_data) # Emit the updated data as a dictionary - self.close() + self.accept() # Close the dialog def get_updated_data_from_table(self): """Convert the table back into a dictionary with any changes made, including the Markdown text.""" @@ -208,20 +220,26 @@ def get_updated_data_from_table(self): # Loop through the table and collect other data for row in range(self.table.rowCount()): key = self.table.item(row, 0).text() # Get the key (read-only) - value_widget = self.table.cellWidget(row, 1) # Get the widget from the second column + value_widget = self.table.cellWidget( + row, 1 + ) # Get the widget from the second column if isinstance(value_widget, ToggleSwitch): updated_value = value_widget.isChecked() elif isinstance(value_widget, QCheckBox): updated_value = value_widget.isChecked() - elif isinstance(value_widget, QSpinBox) or isinstance(value_widget, QDoubleSpinBox): + elif isinstance(value_widget, QSpinBox) or isinstance( + value_widget, QDoubleSpinBox + ): updated_value = value_widget.value() elif isinstance(value_widget, QComboBox): updated_value = value_widget.currentText() else: updated_value = value_widget.text() # Default to text value - updated_data[key] = updated_value # Update the dictionary with the key-value pair + updated_data[key] = ( + updated_value # Update the dictionary with the key-value pair + ) # Include the Markdown text from the left text edit updated_data["Text"] = self.text_edit_left.toPlainText() From e5e578e027e3225fe2b9caff2a10a634e554f9e3 Mon Sep 17 00:00:00 2001 From: Tim Sutton Date: Wed, 18 Sep 2024 07:54:50 +0100 Subject: [PATCH 3/5] Tidy up layer dialog --- geest/gui/layer_detail_dialog.py | 78 +++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/geest/gui/layer_detail_dialog.py b/geest/gui/layer_detail_dialog.py index af3e5e92..fb6a2cc7 100644 --- a/geest/gui/layer_detail_dialog.py +++ b/geest/gui/layer_detail_dialog.py @@ -1,28 +1,32 @@ import re from qgis.PyQt.QtWidgets import ( + QButtonGroup, + QCheckBox, + QComboBox, QDialog, - QVBoxLayout, - QLabel, - QTableWidget, - QTableWidgetItem, - QPushButton, + QDialogButtonBox, + QDoubleSpinBox, + QFrame, + QHBoxLayout, QHeaderView, + QLabel, QLineEdit, - QCheckBox, + QPushButton, + QRadioButton, + QSizePolicy, + QSpacerItem, QSpinBox, - QDoubleSpinBox, - QComboBox, - QHBoxLayout, + QSplitter, + QTableWidget, + QTableWidgetItem, QTextEdit, + QVBoxLayout, QWidget, - QSplitter, - QFrame, - QRadioButton, - QButtonGroup, - QDialogButtonBox ) +from qgis.PyQt.QtGui import QPixmap from qgis.PyQt.QtCore import Qt, pyqtSignal from .toggle_switch import ToggleSwitch +from geest.utilities import resources_path class LayerDetailDialog(QDialog): @@ -46,6 +50,28 @@ def __init__(self, layer_name, layer_data, tree_item, editing=False, parent=None self.resize(800, 600) # Set a wider dialog size layout.setContentsMargins(20, 20, 20, 20) # Add padding around the layout + self.title_label = QLabel( + "Geospatial Assessment of Women Employment and Business Opportunities in the Renewable Energy Sector", + self, + ) + self.title_label.setWordWrap(True) + layout.addWidget(self.title_label) + # Get the grandparent and parent items + grandparent_item = tree_item.parent().parent() if tree_item.parent() else None + parent_item = tree_item.parent() + + # If both grandparent and parent exist, create the label + if grandparent_item and parent_item: + hierarchy_label = QLabel( + f"{grandparent_item.data(0)} :: {parent_item.data(0)}" + ) + hierarchy_label.setStyleSheet( + "font-size: 14px; font-weight: bold; color: gray;" + ) + layout.addWidget( + hierarchy_label, alignment=Qt.AlignTop + ) # Add the label above the heading + # Heading for the dialog heading_label = QLabel(layer_name) heading_label.setStyleSheet( @@ -55,11 +81,16 @@ def __init__(self, layer_name, layer_data, tree_item, editing=False, parent=None heading_label, alignment=Qt.AlignTop ) # Align heading at the top - # Line separator between heading and text edits - line = QFrame() - line.setFrameShape(QFrame.HLine) - line.setFrameShadow(QFrame.Sunken) - layout.addWidget(line) + self.banner_label = QLabel() + self.banner_label.setPixmap( + QPixmap(resources_path("resources", "geest-banner.png")) + ) + self.banner_label.setScaledContents(True) # Allow image scaling + self.banner_label.setSizePolicy( + QSizePolicy.Expanding, QSizePolicy.Fixed + ) # Stretch horizontally, fixed vertically + + layout.addWidget(self.banner_label) # Create a horizontal splitter to hold both the Markdown editor and the preview splitter = QSplitter(Qt.Horizontal) @@ -85,6 +116,12 @@ def __init__(self, layer_name, layer_data, tree_item, editing=False, parent=None # Connect the Markdown editor (left) to update the preview (right) in real-time self.text_edit_left.textChanged.connect(self.update_preview) + # Add an expanding spacer to push content above it upwards and below it downwards + expanding_spacer = QSpacerItem( + 20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding + ) + layout.addSpacerItem(expanding_spacer) + # Create the QTableWidget for other properties self.table = QTableWidget() self.table.setColumnCount(2) # Two columns (Key and Value) @@ -243,6 +280,5 @@ def get_updated_data_from_table(self): # Include the Markdown text from the left text edit updated_data["Text"] = self.text_edit_left.toPlainText() - - return updated_data + return updated_data From 1df85532294a3848b367fbc9e82d0327092ed4c3 Mon Sep 17 00:00:00 2001 From: Tim Sutton Date: Wed, 18 Sep 2024 18:13:33 +0100 Subject: [PATCH 4/5] Tidy up spreadsheet, model and spreadsheet parser. --- geest/core/generate_model.py | 74 +++++++--- geest/resources/geest2.ods | Bin 29136 -> 30083 bytes geest/resources/model.json | 262 ++++++++++++++++++----------------- 3 files changed, 185 insertions(+), 151 deletions(-) diff --git a/geest/core/generate_model.py b/geest/core/generate_model.py index 40226883..cced08c4 100755 --- a/geest/core/generate_model.py +++ b/geest/core/generate_model.py @@ -13,7 +13,7 @@ def __init__(self, spreadsheet_path): """ self.spreadsheet_path = spreadsheet_path self.dataframe = None - self.result = {"dimensions": []} # Correct capitalization to match the usage + self.result = {"dimensions": []} def load_spreadsheet(self): """ @@ -23,11 +23,15 @@ def load_spreadsheet(self): self.dataframe = pd.read_excel(self.spreadsheet_path, engine="odf", skiprows=1) print(self.dataframe.columns) - # Select only the relevant columns + # Select only the relevant columns, including the new layer columns self.dataframe = self.dataframe[ [ "Dimension", + "Dimension Required", + "Default Dimension Analysis Weighting", "Factor", + "Factor Required", + "Default Factor Dimension Weighting", "Layer", "ID", "Text", @@ -53,6 +57,8 @@ def load_spreadsheet(self): "Use Poly per Cell", "Use Polyline per Cell", "Use Point per Cell", + "Analysis Mode", # New column + "Layer Required" # New column ] ] @@ -60,6 +66,12 @@ def load_spreadsheet(self): self.dataframe["Dimension"] = self.dataframe["Dimension"].ffill() self.dataframe["Factor"] = self.dataframe["Factor"].ffill() + def create_id(self, name): + """ + Helper method to create a lowercase, underscore-separated id from the name. + """ + return name.lower().replace(" ", "_") + def parse_to_json(self): """ Parse the dataframe into the hierarchical JSON structure. @@ -69,12 +81,44 @@ def parse_to_json(self): for _, row in self.dataframe.iterrows(): dimension = row["Dimension"] factor = row["Factor"] + + # Prepare dimension data + dimension_id = self.create_id(dimension) + dimension_required = row["Dimension Required"] if not pd.isna(row["Dimension Required"]) else "" + default_dimension_analysis_weighting = row["Default Dimension Analysis Weighting"] if not pd.isna(row["Default Dimension Analysis Weighting"]) else "" + + # If the Dimension doesn't exist yet, create it + if dimension not in dimension_map: + new_dimension = { + "id": dimension_id, + "name": dimension, + "required": dimension_required, + "default_analysis_weighting": default_dimension_analysis_weighting, + "factors": [] + } + self.result["dimensions"].append(new_dimension) + dimension_map[dimension] = new_dimension + + # Prepare factor data + factor_id = self.create_id(factor) + factor_required = row["Factor Required"] if not pd.isna(row["Factor Required"]) else "" + default_factor_dimension_weighting = row["Default Factor Dimension Weighting"] if not pd.isna(row["Default Factor Dimension Weighting"]) else "" + + # If the Factor doesn't exist in the current dimension, add it + factor_map = {f["name"]: f for f in dimension_map[dimension]["factors"]} + if factor not in factor_map: + new_factor = { + "id": factor_id, + "name": factor, + "required": factor_required, + "default_dimension_weighting": default_factor_dimension_weighting, + "layers": [] + } + dimension_map[dimension]["factors"].append(new_factor) + factor_map[factor] = new_factor + + # Add layer data to the current Factor, including new columns layer_data = { - # These are initially blank for the user to make choices - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", # These are all parsed from the spreadsheet "Layer": row["Layer"] if not pd.isna(row["Layer"]) else "", "ID": row["ID"] if not pd.isna(row["ID"]) else "", @@ -185,22 +229,10 @@ def parse_to_json(self): if not pd.isna(row["Use Point per Cell"]) else "" ), + "Analysis Mode": row["Analysis Mode"] if not pd.isna(row["Analysis Mode"]) else "", # New column + "Layer Required": row["Layer Required"] if not pd.isna(row["Layer Required"]) else "" # New column } - # If the Dimension doesn't exist yet, create it - if dimension not in dimension_map: - new_dimension = {"name": dimension, "factors": []} - self.result["dimensions"].append(new_dimension) - dimension_map[dimension] = new_dimension - - # If the Factor doesn't exist in the current dimension, add it - factor_map = {f["name"]: f for f in dimension_map[dimension]["factors"]} - if factor not in factor_map: - new_factor = {"name": factor, "layers": []} - dimension_map[dimension]["factors"].append(new_factor) # Correct variable name - factor_map[factor] = new_factor - - # Add layer data to the current Factor factor_map[factor]["layers"].append(layer_data) def get_json(self): diff --git a/geest/resources/geest2.ods b/geest/resources/geest2.ods index e49899cd64e9ecf2c58852ef552d6927b5145819..2c1938ed9db934a6f554a8a4080317ae1364b256 100644 GIT binary patch delta 20758 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 Jgv{#_{SQpvUWEVv delta 19744 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 diff --git a/geest/resources/model.json b/geest/resources/model.json index 1ab57eea..1504f618 100644 --- a/geest/resources/model.json +++ b/geest/resources/model.json @@ -1,16 +1,18 @@ { "dimensions": [ { + "id": "contextual", "name": "Contextual", + "required": 1.0, + "default_analysis_weighting": 0.33, "factors": [ { + "id": "workplace_discrimination", "name": "Workplace Discrimination", + "required": 1.0, + "default_dimension_weighting": 0.33, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "WBL 2024 Workplace Index Score", "ID": "Workplace_Index", "Text": "Workplace DiscriminationThis tab 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.Input: The input field takes in the WBL index score.Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 indicates areas with a high level of workplace discrimination afforded to women, whereas a value of 0 indicates areas where no workplace discrimination are afforded to women. ", @@ -35,18 +37,19 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] }, { + "id": "regulatory_frameworks", "name": "Regulatory Frameworks", + "required": 1.0, + "default_dimension_weighting": 0.33, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "WBL 2024 Pay+Parenthood Index Score", "ID": "Pay_Parenthood_Index", "Text": "Regulatory FrameworksThis tab computes a raster containing a standardized measure of the regulatory frameworks afforded to women in the country of interest. Input: The input fields take in the WBL Pay and Parenthood Index Scores percentage that represents the level of protective policies afforded to women. The calculation of this percentage is described in detail in the methodological framework document. Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 indicates areas with a high level of protective policies afforded to women, whereas a value of 0 indicates areas where no protective policies are afforded to women. ", @@ -71,18 +74,19 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] }, { + "id": "financial_inclusion", "name": "Financial Inclusion", + "required": 1.0, + "default_dimension_weighting": 0.34, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "WBL 2024 Entrepeneurship Index Score", "ID": "Entrepeneurship_Index ", "Text": "Financial InclusionThis tab computes a raster containing a standardized measure of the percentage of women who have a bank account or have borrowed from a formal financial institution. Input: The input field takes in the percentage of women who have a bank account (WBL Entrepeneurship Index Score). Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 signifies areas where all women possess a bank account or have borrowed from a formal financial institution, whereas a value of 0 represents areas where no women have a bank account or have borrowed from a formal institution. ", @@ -107,23 +111,27 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] } ] }, { + "id": "accessibility", "name": "Accessibility", + "required": 0.0, + "default_analysis_weighting": 0.33, "factors": [ { + "id": "women's_travel_patterns", "name": "Women's Travel Patterns", + "required": 1.0, + "default_dimension_weighting": 0.2, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Location of kindergartens/childcare", "ID": "Kindergartens_Location", "Text": "Women's Travel PatternsThis tab estimates the ease with which women can access amenities related to their role as caregivers through a service area network anaysis facilitated using Openrouteservices' (ORS) isochrones service. Isochrones are derived from the OpenStreetMap (OSM) road network with the use of travel distances or times as input to estimate ease of access to the input locations at five incrementally increasing measurement intervals. The largest interval being the maximum distance or time women would travel to reach these locations. The algorithm produces five catchment areas based on the road network. A scoring system ranging from 5 to 1 is assigned to the catchment area polygons, reflecting the decreasing order of accessibility. Areas outside these catchment areas receive a score of zero.Step 1: This step is repeated for each facility type. Input: Point locations (.shp) of amenities related to women's role as caregivers, including childcare, primary and secondary schools, markets, grocery stores and recreational areas. Travel mode: The user can select walking or driving as a travel mode and it is recommended that the same travel mode should be selected for all accessibility factors. The default travel mode is walking due to its inclusive nature. Measurement: The default measurement for travel is distance in meters which is most appropriate for walking. If driving is selected as travel mode, time in minutes is a more appropriate measurement. Travel increments: The travel increments for walking are loaded by default and based on evidence from literature. If evidence from the local context suggests alternative thresholds and increments are more appropriate, the user can alter these default values. If the selected travel mode is driving the equal measurement increments should be in minutes, and informed by the local context (for example, if the user knows that the maximum time that women spend driving is 30 minutes, the increment input would be 6, 12, 18, 24, 30). Step 2: The algorithm aggregates all raster layers created in step 1 by calculating the mean score for each pixel. Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 identifies areas that are within the catchment defined by the smallest travel increment for all amenities (i.e., the areas where accessibility for women is highest). A value of 0 indicates areas that are outside of the catchment defined by the maximum travel increment for all amenities (i.e., no amenities are accessible to women from these areas). Service Area Analysis is undertaken using the openrouteservice API and OpenStreetMap data. \u00a9 openrouteservice.org by HeiGIT | Road network data \u00a9 OpenStreetMap contributors", @@ -148,13 +156,11 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 }, { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Location of primary schools ", "ID": "Primary_School_Location", "Text": "", @@ -179,13 +185,11 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 }, { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Location of groceries", "ID": "Groceries_Location", "Text": "", @@ -210,13 +214,11 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 }, { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Location of pharmacies", "ID": "Pharmacies_Location", "Text": "", @@ -241,13 +243,11 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 }, { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Location of green spaces ", "ID": "Green_Space_location", "Text": "", @@ -272,18 +272,19 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] }, { + "id": "access_to_public_transport", "name": "Access to Public Transport", + "required": 1.0, + "default_dimension_weighting": 0.2, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Location of public transportation stops, including maritime", "ID": "Pulic_Transport_location", "Text": "Access to Public TransportThis tab estimates the ease with which women can access public transport stops through a service area network anaysis facilitated using Openrouteservices' (ORS) isochrones service. Isochrones are derived from the OpenStreetMap (OSM) road network with the use of travel distances or times as input to estimate ease of access to the public transport stops at five incrementally increasing measurement intervals. The largest interval being the maximum distance or time women would travel to reach these locations. The algorithm produces five catchment areas based on the road network. A scoring system ranging from 5 to 1 is assigned to the catchment area polygons, reflecting the decreasing order of accessibility. Areas outside these catchment areas receive a score of zero. Input: Point locations (.shp) of public transport stops. Travel mode: The user can select walking or driving as a travel mode and it is recommended that the same travel mode should be selected for all accessibility factors. The default travel mode is walking due to its inclusive nature. Measurement: The default measurement for travel is distance in meters which is most appropriate for walking. If driving is selected as travel mode, time in minutes is a more appropriate measurement. Travel increments: The travel increments for walking are loaded by default and based on evidence from literature. If evidence from the local context suggests alternative thresholds and increments are more appropriate, the user can alter these default values. If the selected travel mode is driving the equal measurement increments should be in minutes, and informed by the local context (for example, if the user knows that the maximum time that women spend driving is 30 minutes, the increment input would be 6, 12, 18, 24, 30). Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 identifies areas that are within the catchment defined by the smallest travel increment for transport stops (i.e., the areas where transport accessibility for women is highest). A value of 0 indicates areas that are outside of the catchment defined by the maximum travel increment for transport stops (i.e., no transport stops are accessible to women from these areas). Service Area Analysis is undertaken using the openrouteservice API and OpenStreetMap data. \u00a9 openrouteservice.org by HeiGIT | Road network data \u00a9 OpenStreetMap contributors", @@ -308,18 +309,19 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] }, { + "id": "access_to_health_facilities", "name": "Access to Health Facilities", + "required": 1.0, + "default_dimension_weighting": 0.2, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Location of hospitals and clinics", "ID": "Hospital_Location", "Text": "Health FacilitiesThis algorithm estimates the ease with which women can access health facilities such as hospitals and women's health clinics through a service area network anaysis facilitated using Openrouteservices' (ORS) isochrones service. Isochrones are derived from the OpenStreetMap (OSM) road network with the use of travel distances or times as input to estimate ease of access to health facilities at five incrementally increasing measurement intervals. The largest interval being the maximum distance or time women would travel to reach these locations. The algorithm produces five catchment areas based on the road network. A scoring system ranging from 5 to 1 is assigned to the catchment area polygons, reflecting the decreasing order of accessibility. Areas outside these catchment areas receive a score of zero. Input: Point locations (.shp) of health facilities such as hospitals and women's health clinics. Travel mode: The user can select walking or driving as a travel mode and it is recommended that the same travel mode should be selected for all accessibility factors. The default travel mode is walking due to its inclusive nature. Measurement: The default measurement for travel is distance in meters which is most appropriate for walking. If driving is selected as travel mode, time in minutes is a more appropriate measurement. Travel increments: The travel increments for walking are loaded by default and based on evidence from literature. If evidence from the local context suggests alternative thresholds and increments are more appropriate, the user can alter these default values. If the selected travel mode is driving the equal measurement increments should be in minutes, and informed by the local context (for example, if the user knows that the maximum time that women spend driving is 30 minutes, the increment input would be 6, 12, 18, 24, 30). Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 identifies areas that are within the catchment defined by the smallest travel increment for a health facility (i.e., the areas where access to health facilities for women is highest). A value of 0 indicates areas that are outside of the catchment defined by the maximum travel increment for health facilities (i.e., no health facilities are accessible to women from these areas). Service Area Analysis is undertaken using the openrouteservice API and OpenStreetMap data. \u00a9 openrouteservice.org by HeiGIT | Road network data \u00a9 OpenStreetMap contributors", @@ -344,18 +346,19 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] }, { + "id": "access_to_education_and_training_facilities", "name": "Access to Education and Training Facilities", + "required": 1.0, + "default_dimension_weighting": 0.2, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Location of universities and technical schools", "ID": "Universities_Location", "Text": "Education and Training FacilitiesThis tab estimates the ease with which women can access universities and technical training facilities through a service area network anaysis facilitated using Openrouteservices' (ORS) isochrones service. Isochrones are derived from the OpenStreetMap (OSM) road network with the use of travel distances or times as input to estimate ease of access to the education facilities at five incrementally increasing measurement intervals. The largest interval being the maximum distance or time women would travel to reach these locations. The algorithm produces five catchment areas based on the road network. A scoring system ranging from 5 to 1 is assigned to the catchment area polygons, reflecting the decreasing order of accessibility. Areas outside these catchment areas receive a score of zero. Input: Point locations (.shp) of universities and technical training facilities. Travel mode: The user can select walking or driving as a travel mode and it is recommended that the same travel mode should be selected for all accessibility factors. The default travel mode is walking due to its inclusive nature. Measurement: The default measurement for travel is distance in meters which is most appropriate for walking. If driving is selected as travel mode, time in minutes is a more appropriate measurement. Travel increments: The travel increments for walking are loaded by default and based on evidence from literature. If evidence from the local context suggests alternative thresholds and increments are more appropriate, the user can alter these default values. If the selected travel mode is driving the equal measurement increments should be in minutes, and informed by the local context (for example, if the user knows that the maximum time that women spend driving is 30 minutes, the increment input would be 6, 12, 18, 24, 30). Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 identifies areas that are within the catchment defined by the smallest travel increment for an education facility (i.e., the areas where access to education facilities for women is highest). A value of 0 indicates areas that are outside of the catchment defined by the maximum travel increment for education facilities (i.e., no education facilities are accessible to women from these areas). Service Area Analysis is undertaken using the openrouteservice API and OpenStreetMap data. \u00a9 openrouteservice.org by HeiGIT | Road network data \u00a9 OpenStreetMap contributors", @@ -380,18 +383,19 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] }, { + "id": "access_to_financial_facilities", "name": "Access to Financial Facilities", + "required": 1.0, + "default_dimension_weighting": 0.2, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Location of Banks and other FF", "ID": "Banks_Location", "Text": "Financial FacilitiesThis algorithm estimates the ease with which women can access financial facilities such as banks and ATMs through a service area network anaysis facilitated using Openrouteservices' (ORS) isochrones service. Isochrones are derived from the OpenStreetMap (OSM) road network with the use of travel distances or times as input to estimate ease of access to financial facilities at five incrementally increasing measurement intervals. The largest interval being the maximum distance or time women would travel to reach these locations. The algorithm produces five catchment areas based on the road network. A scoring system ranging from 5 to 1 is assigned to the catchment area polygons, reflecting the decreasing order of accessibility. Areas outside these catchment areas receive a score of zero. Input: Point locations (.shp) of financial facilities such as banks and ATMs. Travel mode: The user can select walking or driving as a travel mode and it is recommended that the same travel mode should be selected for all accessibility factors. The default travel mode is walking due to its inclusive nature. Measurement: The default measurement for travel is distance in meters which is most appropriate for walking. If driving is selected as travel mode, time in minutes is a more appropriate measurement. Travel increments: The travel increments for walking are loaded by default and based on evidence from literature. If evidence from the local context suggests alternative thresholds and increments are more appropriate, the user can alter these default values. If the selected travel mode is driving the equal measurement increments should be in minutes, and informed by the local context (for example, if the user knows that the maximum time that women spend driving is 30 minutes, the increment input would be 6, 12, 18, 24, 30). Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 identifies areas that are within the catchment defined by the smallest travel increment for a financial facility (i.e., the areas where access to financial facilities for women is highest). A value of 0 indicates areas that are outside of the catchment defined by the maximum travel increment for financial facilities (i.e., no financial facilities are accessible to women from these areas). Service Area Analysis is undertaken using the openrouteservice API and OpenStreetMap data. \u00a9 openrouteservice.org by HeiGIT | Road network data \u00a9 OpenStreetMap contributors", @@ -416,23 +420,27 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] } ] }, { + "id": "place_characterization", "name": "Place Characterization", + "required": 1.0, + "default_analysis_weighting": 0.34, "factors": [ { + "id": "active_transport", "name": "Active Transport", + "required": 1.0, + "default_dimension_weighting": 0.1, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Location of street crossings", "ID": "Street_Crossing_Location", "Text": "Active TransportThis tab defines areas based on the degree to which they support safe and efficient active transport (walking, cycling and other forms of non-motorized transport) for women, through the classification of road type. Input: A road network polyline layer (.shp) such as cycle paths, and pathways. A point layer (.shp) such as crosswalks points. A polygon (.shp) for blocks.Process: The user inputs all the required layers. The territory is then divided into 100m by 100m rasters.If there:- No features in a raster cell, a value of 0 is assigned.- Is 1 feature in a raster cell, a value of 3 is assigned.- Are 2 or more features in a raster cell, a value of 5 is assigned.Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 indicates areas that are most conducive to active transport. A value of 3 indicates areas that are least conducive to active transport. A value of 0 indicates areas where there are no roads at all, and thus active transport is assumed to be impossible.", @@ -457,13 +465,11 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 1 + "Use Point per Cell": 1, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 }, { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Location of cycle paths", "ID": "Cycle_Paths_Location", "Text": "", @@ -488,13 +494,11 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 1, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 }, { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Location of footpaths", "ID": "Footpaths_Location", "Text": "", @@ -519,13 +523,11 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 1, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 }, { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Block Layout", "ID": "Block_Layout", "Text": "", @@ -550,18 +552,19 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 1, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] }, { + "id": "safety", "name": "Safety", + "required": 1.0, + "default_dimension_weighting": 1.0, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Street lights/Nigthttime ligths", "ID": "Street_Lights", "Text": "SafetyThis tab defines areas based on how brightly lit they are and assumes that brightly lit areas are safer than areas with no lights.nput: Streetlight Locations (.shp, Point) or, if unavailable, VIIRS Nighttime Lights dataset (.tif) may be used as proxy data for streetlight locations. Alternatively, Perceived Safety data (.shp, Polygon) can be used if other data is unavailable. (Important note: If used for assessing safe urban design, nighttime lights should be excluded from the calculation of Electrical access.)Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 indicates the most brightly lit areas and by assumption the safest areas. 0 represents areas with no nighttime lights and by assumption the least safe areas.", @@ -586,18 +589,19 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 1, "Use Polyline per Cell": 1, - "Use Point per Cell": 1 + "Use Point per Cell": 1, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] }, { + "id": "fcv", "name": "FCV", + "required": 1.0, + "default_dimension_weighting": 1.0, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "ACLED data (Violence Estimated Events)", "ID": "FCV", "Text": "Fragility, conflict, and violenceThis indicator is structured by assigning scores to rasters based on their overlap with buffers indicating different types of events. Input: ACLED data as a csv file (.csv). If the impact radius of an event is known, it should be used instead.Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. Regions with score of 0 overlap with bufers of serious events. Regions with a score of 5 do not overlap with buffers of any event/s.Warning: The processing may take a very long time to complete, during which QGIS might become unresponsive. ", @@ -622,18 +626,19 @@ "Use CSV to Point Layer": 1, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] }, { + "id": "education", "name": "Education", + "required": 1.0, + "default_dimension_weighting": 1.0, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "percentage of the labor force comprising women with university degrees ", "ID": "Education", "Text": "EducationThis tab computes a raster containing a standardized measure of the percentage of women who have achieved a post-secondary education in the country of interest. Input: A Polygon layer (.shp) containing a field reporting the percentage of women who have achieved a post-secondary education. If a polygon layer is not available, the Education Level Value may be set manually, in which case the entirity of the administrative area will be assigned the supplied value.Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 indicates regions where all women have completed post-secondary education, whereas a value of 0 indicates areas where no women have attained post-secondary education. ", @@ -658,18 +663,19 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 1, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] }, { + "id": "digital_inclusion", "name": "Digital Inclusion", + "required": 1.0, + "default_dimension_weighting": 1.0, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Individuals using the Internet (% of population)", "ID": "Digital_Inclusion", "Text": "Digital InclusionThis tab characterizes areas based on the percentage of houses with access to the Internet. Input: A polygon (.shp) with the value or a value representing the percentage of houses with Internet access (The Internet Access value can be used if there is no polygon input). If your input is a polygon, click on set to populate the fields of interest then select the specific field.Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 indicates areas where all houses have access to the Internet while 0 indicates areas where no houses have Internet access. ", @@ -694,18 +700,19 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 1, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] }, { + "id": "environmental_hazards", "name": "Environmental Hazards", + "required": 1.0, + "default_dimension_weighting": 1.0, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Fire Hazards", "ID": "Fire", "Text": "Environmental HazardsThis tab characterizes areas based on their vulnerability to environmental hazards.Input: One or many raster layers.The hazard datasets used are:1. Forest Fire: Active Fires Density (2003 - 2004)2. Flood: Flood Hazard3. Landslide: Landslide Susceptibility4. Tropical Cyclone: Frequency of Tropical Cyclones5. Drought: Global Drought Hazard based on the Standardized Precipitation Evapotranspiration Index (SPEI)Step 1 For each layer representing a different class of environmental hazard, the input layer is set. The algorithm reclassifies the input field such that low-risk areas are assigned a score of 5, medium-risk areas are assigned a score of 2, and high-risk areas are assigned a score of 0. Step 2 The algorithm identifies all raster layers created in step 1 and aggregates them by calculating the mean score for each pixel. The default raster output filename does not need to be altered unless the user wishes. Output: A raster file containing values ranging from 0 to 5 is saved to the output directory. A value of 5 indicates areas where natural disaster risk is lowest. A value of 0 indicates areas where environmental hazard risk is highest. ", @@ -730,13 +737,11 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 }, { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Flood Hazards", "ID": "Flood", "Text": "", @@ -761,13 +766,11 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 }, { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Landslide", "ID": "Landslide", "Text": "", @@ -792,13 +795,11 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 }, { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Tropical Cyclone", "ID": "Cyclone", "Text": "", @@ -823,13 +824,11 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 }, { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Drought", "ID": "Drought", "Text": "", @@ -854,18 +853,19 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] }, { + "id": "water_sanitation", "name": "Water sanitation", + "required": 1.0, + "default_dimension_weighting": 1.0, "layers": [ { - "Analysis Mode": "", - "Points Per Cell Layer": "", - "Lines Per Cell Layer": "", - "Polygons Per Cell Layer": "", "Layer": "Water points (OSM), catch basins, water valves and fire hydrants", "ID": "", "Text": "Water and SanitationThis tab generates a raster map representing the spatial distribution of water and sanitation services across the country of interest.Input: Point layer (.shp) of water and sanitation facility locationsProcess: The tool creates a 1000-meter buffer around each water/sanitation point, assigns a score of 5 to each, then rasterizes this data. The output raster is composed of cells at the prefered resolution specified in the Setup tab. Each cell is assigned a value based on proximity to water/sanitation points:5: Within 1000 meters of one or more water/sanitation points0: No water/sanitation points within 1000 metersOutput: A raster file with values ranging from 0 to 5, where higher values indicate areas with better access to water and sanitation services.", @@ -890,7 +890,9 @@ "Use CSV to Point Layer": 0, "Use Poly per Cell": 0, "Use Polyline per Cell": 0, - "Use Point per Cell": 0 + "Use Point per Cell": 0, + "Analysis Mode": "Don\u2019t Use", + "Layer Required": 1 } ] } From e563406ca478be54015e9c158cacb8681094e3a9 Mon Sep 17 00:00:00 2001 From: Tim Sutton Date: Wed, 18 Sep 2024 18:32:45 +0100 Subject: [PATCH 5/5] Tidy up dialog more --- geest/gui/layer_detail_dialog.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/geest/gui/layer_detail_dialog.py b/geest/gui/layer_detail_dialog.py index fb6a2cc7..a93975ef 100644 --- a/geest/gui/layer_detail_dialog.py +++ b/geest/gui/layer_detail_dialog.py @@ -232,9 +232,22 @@ def add_config_widgets(self, layout): self.button_group.addButton(radio_button) # Add a label next to the radio button with the key's name - label = QLabel(key) - frame_layout.addWidget(label) + #label = QLabel(key) + #frame_layout.addWidget(label) + # Check the first radio button by default + if key == self.layer_data.get("Analysis Mode"): + radio_button.setChecked(True) + + # Add the radio button to the button group + self.button_group.addButton(radio_button) + + if not self.layer_data.get("Layer Required"): + radio_button = QRadioButton("Don't use") + self.radio_buttons.append(radio_button) + frame_layout.addWidget(radio_button) + #label = QLabel( "Don't use this layer") + #frame_layout.addWidget(label) frame.setLayout(frame_layout) layout.addWidget(frame)