Source code for uwsift.view.dataset_statistics_pane

import numbers
from decimal import Decimal
from typing import Tuple

import numpy as np
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont

from uwsift.common import Info
from uwsift.model.layer_item import LayerItem
from uwsift.ui.dataset_statistics_widget_ui import Ui_datasetStatisticsPane


[docs] class DatasetStatisticsPane(QtWidgets.QWidget): """The purpose of this class is to manage the statistic analysis pane. In the statistical analysis pane, the corresponding statistics of the first active dataset of a selected layer are displayed. """ def __init__(self, *args, **kwargs): super(DatasetStatisticsPane, self).__init__(*args, **kwargs) layout = QtWidgets.QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) self.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) self._pane_ui = Ui_datasetStatisticsPane() self._pane_widget = QtWidgets.QWidget(self) self._pane_ui.setupUi(self._pane_widget) layout.addWidget(self._pane_widget) self.setLayout(layout) self._pane_ui.datasetNameLabel.setText("") self._pane_ui.decimalPlacesSpinBox.setValue(2) self._pane_ui.decimalPlacesSpinBox.valueChanged.connect(self._decimal_places_changed) self._current_selected_layer = None self._pane_ui.statisticsTableWidget.setSelectionMode(QtWidgets.QTableWidget.SingleSelection) self._pane_ui.statisticsTableWidget.resizeColumnsToContents() self._pane_ui.statisticsTableWidget.horizontalHeader().setStretchLastSection(True) # Slot functions
[docs] def initiate_update(self): """Refresh the display of name and the statistics from the current active dataset or clear the pane if there is none. """ self._clear_statistics_pane() # TODO: start revision here if you want to keep parts of the table layout if not self._current_selected_layer: return first_active_dataset = self._current_selected_layer.get_first_active_product_dataset() if not first_active_dataset: return dataset_display_name = ( f"{self._current_selected_layer.descriptor} {first_active_dataset.info[Info.DISPLAY_TIME]}" ) self._pane_ui.datasetNameLabel.setText(dataset_display_name) stats = self._current_selected_layer.model._workspace.get_statistics_for_dataset_by_uuid( first_active_dataset.uuid ) self._update_table_content(stats)
def _decimal_places_changed(self): if self._current_selected_layer: first_active_dataset = self._current_selected_layer.get_first_active_product_dataset() if first_active_dataset: stats = self._current_selected_layer.model._workspace.get_statistics_for_dataset_by_uuid( first_active_dataset.uuid ) self._update_table_content(stats)
[docs] def selection_did_change(self, layers: Tuple[LayerItem]): """Process if an update is needed or not. If it is then initiate the update process If multiple layers are selected then the statistics can not be viewed. """ if layers is not None and len(layers) == 1: self._current_selected_layer = layers[0] else: self._current_selected_layer = None self.initiate_update()
# Utility functions def _clear_statistics_pane(self): self._pane_ui.datasetNameLabel.setText("") self._pane_ui.statisticsTableWidget.setRowCount(0) self._pane_ui.statisticsTableWidget.setColumnCount(0) self._pane_ui.statisticsTableWidget.verticalHeader().show() self._pane_ui.statisticsTableWidget.horizontalHeader().show() @staticmethod def _determine_rounded_value(decimal_places: int, value: Decimal): if decimal_places > 1: decimal_places_str = f"{0:.{decimal_places - 1}f}1" elif decimal_places == 1: decimal_places_str = ".1" else: decimal_places_str = "1." value = value.quantize(Decimal(decimal_places_str)) return value def _determine_table_content_by_stats_dict(self, stats: dict, header: list): keys = list(stats.keys()) max_col_number = 0 for key in keys: cur_col_number = len(stats[key]) if cur_col_number > max_col_number: max_col_number = cur_col_number self._pane_ui.statisticsTableWidget.setRowCount(len(stats)) self._pane_ui.statisticsTableWidget.setColumnCount(max_col_number) self._pane_ui.statisticsTableWidget.setVerticalHeaderLabels(list(stats.keys())) if header: self._pane_ui.statisticsTableWidget.setHorizontalHeaderLabels(header) else: self._pane_ui.statisticsTableWidget.horizontalHeader().hide() for row in range(len(stats)): curr_stat = stats[keys[row]] for col in range(len(curr_stat)): value = self._determine_value_for_table_item(curr_stat[col]) item = self._get_tailored_item(value) self._pane_ui.statisticsTableWidget.setItem(row, col, item) def _determine_table_content_by_stats_list(self, stats: list, header: list): self._pane_ui.statisticsTableWidget.verticalHeader().hide() max_col_number = 0 for row in stats: cur_col_number = len(row) if cur_col_number > max_col_number: max_col_number = cur_col_number self._pane_ui.statisticsTableWidget.setRowCount(len(stats)) self._pane_ui.statisticsTableWidget.setColumnCount(max_col_number) if header: self._pane_ui.statisticsTableWidget.horizontalHeader().show() self._pane_ui.statisticsTableWidget.setHorizontalHeaderLabels(header) else: self._pane_ui.statisticsTableWidget.horizontalHeader().hide() for row in range(len(stats)): row_content = stats[row] for col in range(len(row_content)): col_content = row_content[col] value = self._determine_value_for_table_item(col_content) item = self._get_tailored_item(value) self._pane_ui.statisticsTableWidget.setItem(row, col, item) def _determine_value_for_table_item(self, value: float) -> str: decimal_places = self._pane_ui.decimalPlacesSpinBox.value() if isinstance(value, np.number): # if the given value is a numeric numpy value then it needs to be converted # to a standard python numeric value because the used Decimal class can't # convert a numpy numeric value to a Decimal class object value = value.item() value_str = str(value) if isinstance(value, numbers.Number): if isinstance(value, int): value_str = str(value) elif decimal_places > -1: value_str = str(self._determine_rounded_value(decimal_places, Decimal(value))) return value_str @staticmethod def _get_tailored_item(value: str) -> QtWidgets.QTableWidgetItem: item = QtWidgets.QTableWidgetItem(value) item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter) font = QFont("Monospace") font.setStyleHint(QFont.TypeWriter) item.setFont(font) item.setFlags(item.flags() & ~Qt.ItemIsEditable) return item def _update_table_content(self, data: dict): stats = data.get("stats") if not stats: return header = data.get("header", []) if isinstance(stats, dict): self._determine_table_content_by_stats_dict(stats, header) elif isinstance(stats, list): self._determine_table_content_by_stats_list(stats, header) self._resize_all_but_the_last_column_to_contents() def _resize_all_but_the_last_column_to_contents(self): for column in range(0, self._pane_ui.statisticsTableWidget.columnCount() - 1): self._pane_ui.statisticsTableWidget.resizeColumnToContents(column)