diff --git a/othello/gis/util.py b/othello/gis/util.py index d4b82b7..f856687 100644 --- a/othello/gis/util.py +++ b/othello/gis/util.py @@ -2,6 +2,7 @@ import functools from typing import Dict, List +import pandas from geopandas import GeoDataFrame from othello.gis import io @@ -19,7 +20,17 @@ def make_dataframe_with_common_columns(dfs: List[GeoDataFrame], common_columns: return df -def add_weighted_columns_to_dataframe(df: GeoDataFrame, criteria_information: List[Dict]) -> GeoDataFrame: +def add_weighted_columns_to_dataframe(df: GeoDataFrame, criteria_information: List[Dict], join_on: str) -> GeoDataFrame: + """Add the weighted criteria to the 'df' dataframe by joining data on the join_on column name. + + Args: + df: Base GeoDataFrame + criteria_information: Criteria data that allows to retrieve the exact column from a table from a layer from aGDB file + join_on: Column name on which the table join will be based + + Returns: + GeoDataFrame with the added criteria and the final score + """ weighted_columns = [] for criterion_information in criteria_information: @@ -29,11 +40,16 @@ def add_weighted_columns_to_dataframe(df: GeoDataFrame, criteria_information: Li weight = criterion_information['weight'] criterion_name = criterion_information['criterion_name'] - criterion_geoseries = io.read(filepath, layer=layer)[field] - df[criterion_name + '_np'] = criterion_geoseries - df[criterion_name + '_p'] = weight * criterion_geoseries + criterion_df = io.read(filepath, layer=layer)[[join_on, field]] + criterion_df.columns = [join_on, criterion_name + '_np'] + criterion_df[criterion_name + '_p'] = weight * criterion_df[criterion_name + '_np'] + + df = pandas.merge(left=df, right=criterion_df, on=join_on) weighted_columns.append(criterion_name + '_p') + # df[criterion_name + '_np'] = criterion_df + # df[criterion_name + '_p'] = weight * criterion_df + # Final score in a new series df['FinalScore'] = [0 for _ in range(len(df))] for column in weighted_columns: diff --git a/othello/ui/aggregate.py b/othello/ui/aggregate.py index f3ed5a0..8d2a6e3 100644 --- a/othello/ui/aggregate.py +++ b/othello/ui/aggregate.py @@ -2,7 +2,7 @@ import geopandas from PySide2 import QtCore, QtWidgets -from PySide2.QtWidgets import QMessageBox +from PySide2.QtWidgets import QInputDialog, QMessageBox from othello import gis from othello.ui import errors @@ -35,7 +35,7 @@ def __init__(self, parent): self.table.setGeometry(QtCore.QRect(20, 80, 731, 400)) self.table.setRowCount(0) self.table.setColumnCount(5) - self.table.setHorizontalHeaderLabels(['Criterion', 'Layer', 'Field', 'Weight [0-1]', 'criterion name']) + self.table.setHorizontalHeaderLabels(['Criterion', 'Layer', 'Field', 'Weight [0-1]', 'Criterion name']) header = self.table.horizontalHeader() header.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch) @@ -71,10 +71,23 @@ def aggregate(self, to_new_file: bool, force_normalized_weights: bool = True): self.assert_weights_are_normalized() common_columns = gis.util.find_common_columns(self.dfs) + + # Choose the column on which the table join will be based + join_on_column, has_not_failed = QInputDialog.getItem( + self, + 'Question', + 'Choose the column on which the table join will be based.', + common_columns, + 0, + False + ) + if not (has_not_failed and join_on_column): + return + df = gis.util.make_dataframe_with_common_columns(self.dfs, common_columns) if to_new_file: - filepath = QtWidgets.QFileDialog.getSaveFileName(self)[0] + filepath = QtWidgets.QFileDialog.getSaveFileName(self, 'Save to file', '', 'GDB (*.gdb)')[0] else: filepath = QtWidgets.QFileDialog.getExistingDirectory(self) @@ -85,7 +98,7 @@ def aggregate(self, to_new_file: bool, force_normalized_weights: bool = True): popup.show() return - df = self.add_weighted_columns(df) + df = self.add_weighted_columns(df, join_on_column) gis.io.write(df, filepath, layer=f'FinalLayer-{datetime.now().strftime("%Y-%m-%d-%H:%M:%S")}') popup = Popup(f'The file "{filepath}" have been written.', self) @@ -154,7 +167,7 @@ def assert_no_duplicates_in_criterion_names(self): criterion_names.add(criterion_name) - def add_weighted_columns(self, df: geopandas.GeoDataFrame) -> geopandas.GeoDataFrame: + def add_weighted_columns(self, df: geopandas.GeoDataFrame, join_on: str) -> geopandas.GeoDataFrame: criteria_information = [] for row_index in range(self.table.rowCount()): @@ -166,7 +179,7 @@ def add_weighted_columns(self, df: geopandas.GeoDataFrame) -> geopandas.GeoDataF 'criterion_name': self.table.item(row_index, 4).text(), }) - df = gis.util.add_weighted_columns_to_dataframe(df, criteria_information) + df = gis.util.add_weighted_columns_to_dataframe(df, criteria_information, join_on=join_on) return df diff --git a/requirements.txt b/requirements.txt index 14f0321..27ab28a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,9 +7,9 @@ click-plugins==1.1.1 cligj==0.7.1 colorama==0.4.4 cx-Freeze==6.5.3 -Fiona @ https://download.lfd.uci.edu/pythonlibs/r4tycu3t/Fiona-1.8.20-cp38-cp38-win_amd64.whl +Fiona @ https://download.lfd.uci.edu/pythonlibs/y2rycu7g/Fiona-1.8.20-cp38-cp38-win_amd64.whl future==0.18.2 -GDAL @ https://download.lfd.uci.edu/pythonlibs/r4tycu3t/GDAL-3.3.1-cp38-cp38-win_amd64.whl +GDAL @ https://download.lfd.uci.edu/pythonlibs/y2rycu7g/GDAL-3.3.1-cp38-cp38-win_amd64.whl geopandas==0.9.0 importlib-metadata==3.7.3 iniconfig==1.1.1 @@ -21,14 +21,14 @@ pefile==2019.4.18 pluggy==0.13.1 py==1.10.0 pyparsing==2.4.7 -pyproj @ https://download.lfd.uci.edu/pythonlibs/r4tycu3t/pyproj-3.0.1-cp38-cp38-win_amd64.whl +pyproj==3.0.1 PySide2==5.15.2 pytest==6.2.2 python-dateutil==2.8.1 pytz==2021.1 pywin32-ctypes==0.2.0 -Rtree @ https://download.lfd.uci.edu/pythonlibs/r4tycu3t/Rtree-0.9.7-cp38-cp38-win_amd64.whl -Shapely @ https://download.lfd.uci.edu/pythonlibs/r4tycu3t/Shapely-1.7.1-cp38-cp38-win_amd64.whl +Rtree==0.9.7 +Shapely==1.7.1 shiboken2==5.15.2 six==1.15.0 toml==0.10.2 diff --git a/tests/gis/test_util.py b/tests/gis/test_util.py index ee6f916..51f9606 100644 --- a/tests/gis/test_util.py +++ b/tests/gis/test_util.py @@ -48,7 +48,7 @@ def test_make_dataframe_with_common_columns(self, dfs, common_columns, expected_ assert list(result.columns) == expected_columns - @pytest.mark.parametrize('df, criteria_info, expected_first_criterion_score, expected_second_criterion_score, expected_first_final_score', [( + @pytest.mark.parametrize('df, criteria_info, join_on_column, expected_first_criterion_score, expected_second_criterion_score, expected_first_final_score', [( geopandas.read_file(GDB_FILEPATH, driver='FileGDB', layer='ArretsTEST_ON'), [{ 'filepath': GDB_FILEPATH, @@ -63,12 +63,13 @@ def test_make_dataframe_with_common_columns(self, dfs, common_columns, expected_ 'weight': .5, 'criterion_name': 'another-criterion', }], + 'ID', (8, 8 * .5), (-46.67, -46.67 * .5), 8 * .5 - 46.67 * .5, )]) - def test_add_weighted_columns_to_dataframe(self, df, criteria_info, expected_first_criterion_score, expected_second_criterion_score, expected_first_final_score): - result = gis.util.add_weighted_columns_to_dataframe(df, criteria_info) + def test_add_weighted_columns_to_dataframe(self, df, criteria_info, join_on_column, expected_first_criterion_score, expected_second_criterion_score, expected_first_final_score): + result = gis.util.add_weighted_columns_to_dataframe(df, criteria_info, join_on_column) assert 'FinalScore' in result.columns assert result['a-criterion_np'][0] == expected_first_criterion_score[0]