From 880f3748b07f3f690f406b83c62b85f418a39eb8 Mon Sep 17 00:00:00 2001 From: janezd Date: Sun, 15 Mar 2020 22:56:38 +0100 Subject: [PATCH] Feature statistics: Reformat numbers --- Orange/widgets/data/owfeaturestatistics.py | 131 +++++++++------------ 1 file changed, 53 insertions(+), 78 deletions(-) diff --git a/Orange/widgets/data/owfeaturestatistics.py b/Orange/widgets/data/owfeaturestatistics.py index 52d28e18905..611afe6cb76 100644 --- a/Orange/widgets/data/owfeaturestatistics.py +++ b/Orange/widgets/data/owfeaturestatistics.py @@ -7,14 +7,13 @@ """ import datetime -import locale from enum import IntEnum from typing import Any, Optional, Tuple, List import numpy as np import scipy.stats as ss import scipy.sparse as sp -from AnyQt.QtCore import Qt, QSize, QRectF, QVariant, QModelIndex, pyqtSlot, \ +from AnyQt.QtCore import Qt, QSize, QRectF, QModelIndex, pyqtSlot, \ QRegExp, QItemSelection, QItemSelectionRange, QItemSelectionModel from AnyQt.QtGui import QPainter, QColor from AnyQt.QtWidgets import QStyledItemDelegate, QGraphicsScene, QTableView, \ @@ -465,44 +464,35 @@ def headerData(self, section, orientation, role): def data(self, index, role): # type: (QModelIndex, Qt.ItemDataRole) -> Any - # Text formatting for various data simply requires a lot of branches. - # This is much better than overengineering various formatters... - # pylint: disable=too-many-branches - - if not index.isValid(): - return None - - row, column = self.mapToSourceRows(index.row()), index.column() - # Make sure we're not out of range - if not 0 <= row <= self.n_attributes: - return QVariant() - - attribute = self.variables[row] - - if role == Qt.BackgroundRole: + def background(): if attribute in self.domain.attributes: return self.COLOR_FOR_ROLE[self.ATTRIBUTE] - elif attribute in self.domain.metas: + if attribute in self.domain.metas: return self.COLOR_FOR_ROLE[self.META] - elif attribute in self.domain.class_vars: + if attribute in self.domain.class_vars: return self.COLOR_FOR_ROLE[self.CLASS_VAR] + return None - elif role == Qt.TextAlignmentRole: + def text_alignment(): if column == self.Columns.NAME: return Qt.AlignLeft | Qt.AlignVCenter return Qt.AlignRight | Qt.AlignVCenter - output = None - - if column == self.Columns.ICON: - if role == Qt.DecorationRole: + def decoration(): + if column == self.Columns.ICON: return gui.attributeIconDict[attribute] - elif column == self.Columns.NAME: - if role == Qt.DisplayRole: - output = attribute.name - elif column == self.Columns.DISTRIBUTION: - if role == Qt.DisplayRole: - if isinstance(attribute, (DiscreteVariable, ContinuousVariable)): + return None + + def display(): + # pylint: disable=too-many-branches + def render_value(value): + return "" if np.isnan(value) else attribute.str_val(value) + + if column == self.Columns.NAME: + return attribute.name + elif column == self.Columns.DISTRIBUTION: + if isinstance(attribute, + (DiscreteVariable, ContinuousVariable)): if row not in self.__distributions_cache: scene = QGraphicsScene(parent=self) histogram = Histogram( @@ -515,60 +505,45 @@ def data(self, index, role): scene.addItem(histogram) self.__distributions_cache[row] = scene return self.__distributions_cache[row] - elif column == self.Columns.CENTER: - if role == Qt.DisplayRole: - if isinstance(attribute, DiscreteVariable): - output = self._center[row] - if not np.isnan(output): - output = attribute.str_val(self._center[row]) - elif isinstance(attribute, TimeVariable): - output = attribute.str_val(self._center[row]) - else: - output = self._center[row] - elif column == self.Columns.DISPERSION: - if role == Qt.DisplayRole: + elif column == self.Columns.CENTER: + return render_value(self._center[row]) + elif column == self.Columns.DISPERSION: if isinstance(attribute, TimeVariable): - output = format_time_diff(self._min[row], self._max[row]) - else: - output = self._dispersion[row] - elif column == self.Columns.MIN: - if role == Qt.DisplayRole: - if isinstance(attribute, DiscreteVariable): - if attribute.ordered: - output = attribute.str_val(self._min[row]) - elif isinstance(attribute, TimeVariable): - output = attribute.str_val(self._min[row]) + return format_time_diff(self._min[row], self._max[row]) + elif isinstance(attribute, DiscreteVariable): + return "%.3g" % self._dispersion[row] else: - output = self._min[row] - elif column == self.Columns.MAX: - if role == Qt.DisplayRole: - if isinstance(attribute, DiscreteVariable): - if attribute.ordered: - output = attribute.str_val(self._max[row]) - elif isinstance(attribute, TimeVariable): - output = attribute.str_val(self._max[row]) - else: - output = self._max[row] - elif column == self.Columns.MISSING: - if role == Qt.DisplayRole: - output = '%d (%d%%)' % ( + return render_value(self._dispersion[row]) + elif column == self.Columns.MIN: + if not isinstance(attribute, DiscreteVariable) \ + or attribute.ordered: + return render_value(self._min[row]) + elif column == self.Columns.MAX: + if not isinstance(attribute, DiscreteVariable) \ + or attribute.ordered: + return render_value(self._max[row]) + elif column == self.Columns.MISSING: + return '%d (%d%%)' % ( self._missing[row], 100 * self._missing[row] / self.n_instances ) + return None + + roles = {Qt.BackgroundRole: background, + Qt.TextAlignmentRole: text_alignment, + Qt.DecorationRole: decoration, + Qt.DisplayRole: display} + + if not index.isValid() or role not in roles: + return None + + row, column = self.mapToSourceRows(index.row()), index.column() + # Make sure we're not out of range + if not 0 <= row <= self.n_attributes: + return None - # Consistently format the text inside the table cells - # The easiest way to check for NaN is to compare with itself - if output != output: # pylint: disable=comparison-with-itself - output = '' - # Format āˆž properly - elif output in (np.inf, -np.inf): - output = '%sāˆž' % ['', '-'][output < 0] - elif isinstance(output, int): - output = locale.format_string('%d', output, grouping=True) - elif isinstance(output, float): - output = locale.format_string('%.2f', output, grouping=True) - - return output + attribute = self.variables[row] + return roles[role]() def rowCount(self, parent=QModelIndex()): return 0 if parent.isValid() else self.n_attributes