Skip to content

Scenario Comparison Table Generator

Scenario comparison table information.

ScenarioComparisonTableInfo

ScenarioComparisonTableInfo(results, parent=None)

Bases: QObject

Get area information for the scenarios in the corresponding ScenarioResult objects and uses this information to generate QgsLayoutTableColumn and QgsTableCell objects for use in a scenario comparison table.

Source code in src/cplus_plugin/lib/reports/comparison_table.py
def __init__(self, results: typing.List[ScenarioResult], parent=None):
    super().__init__(parent)

    self._scenario_results = results
    self._activity_header_info = []
    self._scenario_activity_name_pixel = {}
    self._contents = []
    self._area_calculated = False
    self._area_feedback = QgsProcessingFeedback()
    self._multistep_area_feedback = QgsProcessingMultiStepFeedback(
        len(results), self._area_feedback
    )

    # Extract the header information and populate mapping of activity
    # pixel value with the corresponding name
    for result in self._scenario_results:
        name_pixel_mapping = {}
        for pixel_value, activity in enumerate(
            result.scenario.weighted_activities, 1
        ):
            activity_info = (str(activity.uuid), activity.name)
            name_pixel_mapping[pixel_value] = activity.name
            if activity_info in self._activity_header_info:
                continue
            self._activity_header_info.append(activity_info)

        self._scenario_activity_name_pixel[
            result.scenario.uuid
        ] = name_pixel_mapping

columns property

columns

Headers for the scenario comparison table.

The columns start with one titled 'Scenario' which will contain the scenario name in the rows.

Returns:

Type Description
list

Table headers based on the activities in the scenarios.

feedback property

feedback

Returns a feedback object for updating or canceling the process of area calculation.

Returns:

Type Description
QgsProcessingFeedback

Feedback for updating or canceling the process.

contents

contents()

Calculates the area of scenario layers and creates the corresponding table rows for use in a QgsLayoutTable derivative.

The area_calculated signal is emitted once for every scenario area calculated or acquired using alternative mechanisms.

This function is idempotent and will only return the results from the first call. Subsequent calls will return the same result.

Returns:

Type Description
list

A nested list containing area information for each scenario.

Source code in src/cplus_plugin/lib/reports/comparison_table.py
def contents(self) -> typing.List[typing.List[QgsTableCell]]:
    """Calculates the area of scenario layers and creates the
    corresponding table rows for use in a QgsLayoutTable
    derivative.

    The `area_calculated` signal is emitted once for every scenario
    area calculated or acquired using alternative mechanisms.

    This function is idempotent and will only return the
    results from the first call. Subsequent calls will return
    the same result.

    :returns: A nested list containing area information for
    each scenario.
    :rtype: list
    """
    if self._area_calculated:
        return self._contents

    result_data = []

    current_step = 0
    self._multistep_area_feedback.setCurrentStep(current_step)

    for result in self._scenario_results:
        if self._area_feedback.isCanceled():
            return self._contents

        layer = layer_from_scenario_result(result)
        if layer is None:
            msg = (
                f"Unable to calculate area for scenario comparison a"
                f"s layer for {result.scenario.name} could not "
                f"be created."
            )
            log(msg)

            current_step += 1
            self._multistep_area_feedback.setCurrentStep(current_step)
            continue

        area_info = calculate_raster_value_area(
            layer, feedback=self._multistep_area_feedback
        )
        int_area_info = {
            int(pixel_value): area for pixel_value, area in area_info.items()
        }
        scenario_area_info = ScenarioAreaInfo(
            result.scenario.name, result.scenario.uuid, int_area_info
        )

        # Remap activity pixel value with the name for the calculated area
        activity_pixel_name_info = self._scenario_activity_name_pixel[
            result.scenario.uuid
        ]
        activity_name_area_info = {
            activity_pixel_name_info[pixel_value]: area
            for pixel_value, area in int_area_info.items()
        }

        self.area_calculated.emit(scenario_area_info)

        if len(int_area_info) == 0:
            msg = "No activity areas from the calculation"
            log(msg)

        row_data = []
        row_data.append(QgsTableCell(result.scenario.name))
        for header_info in self._activity_header_info:
            activity_name = header_info[1]
            if activity_name in activity_name_area_info:
                activity_area = activity_name_area_info[activity_name]
            else:
                activity_area = self.NOT_AVAILABLE_STR

            area_cell = QgsTableCell(activity_area)
            area_cell.setHorizontalAlignment(QtCore.Qt.AlignHCenter)
            if isinstance(activity_area, Number):
                number_format = QgsBasicNumericFormat()
                number_format.setThousandsSeparator(",")
                number_format.setShowTrailingZeros(True)
                number_format.setNumberDecimalPlaces(self.AREA_DECIMAL_PLACES)
                area_cell.setNumericFormat(number_format)

            row_data.append(area_cell)

        result_data.append(row_data)

        current_step += 1
        self._multistep_area_feedback.setCurrentStep(current_step)

    self._contents = result_data
    self._area_calculated = True

    return self._contents

Last update: October 2, 2024
Back to top