Skip to content

Commit

Permalink
Merge pull request #4536 from janezd/feature-statistic-number-formatting
Browse files Browse the repository at this point in the history
Feature statistics: Reformat numbers
  • Loading branch information
janezd authored Apr 2, 2020
2 parents bd2f7ec + 880f374 commit 4ad7608
Showing 1 changed file with 53 additions and 78 deletions.
131 changes: 53 additions & 78 deletions Orange/widgets/data/owfeaturestatistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -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, \
Expand Down Expand Up @@ -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(
Expand All @@ -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
Expand Down

0 comments on commit 4ad7608

Please sign in to comment.