Skip to content

Commit b4a9e28

Browse files
committed
state_summary: Provide classes for automated output summary
1 parent 7d2e9ff commit b4a9e28

File tree

2 files changed

+120
-21
lines changed

2 files changed

+120
-21
lines changed

Orange/widgets/utils/state_summary.py

Lines changed: 118 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
1-
from Orange.data import StringVariable, DiscreteVariable, ContinuousVariable, \
2-
TimeVariable
1+
from datetime import date
2+
from html import escape
3+
4+
from AnyQt.QtCore import Qt
5+
6+
from orangewidget.utils.signals import summarize, PartialSummary
7+
8+
from Orange.data import (
9+
StringVariable, DiscreteVariable, ContinuousVariable, TimeVariable,
10+
Table
11+
)
12+
13+
from Orange.evaluation import Results
14+
from Orange.misc import DistMatrix
15+
from Orange.preprocess import Preprocess
16+
from Orange.preprocess.score import Scorer
17+
from Orange.widgets.utils.signals import AttributeList
18+
from Orange.base import Model, Learner
319

420

521
def format_variables_string(variables):
@@ -37,7 +53,11 @@ def format_variables_string(variables):
3753
return var_string
3854

3955

40-
def format_summary_details(data):
56+
def _plural(number):
57+
return 's' * (number % 100 != 1)
58+
59+
60+
def format_summary_details(data, format=Qt.PlainText):
4161
"""
4262
A function that forms the entire descriptive part of the input/output
4363
summary.
@@ -46,31 +66,53 @@ def format_summary_details(data):
4666
:type data: Orange.data.Table
4767
:return: A formatted string
4868
"""
49-
def _plural(number):
50-
return 's' * (number != 1)
51-
52-
details = ''
53-
if data:
54-
features = format_variables_string(data.domain.attributes)
55-
targets = format_variables_string(data.domain.class_vars)
56-
metas = format_variables_string(data.domain.metas)
57-
58-
features_missing = missing_values(data.has_missing_attribute()
59-
and data.get_nan_frequency_attribute())
60-
n_features = len(data.domain.variables) + len(data.domain.metas)
69+
if data is None:
70+
return ""
71+
72+
if format == Qt.PlainText:
73+
def b(s):
74+
return s
75+
else:
76+
def b(s):
77+
return f"<b>{s}</b>"
78+
79+
features = format_variables_string(data.domain.attributes)
80+
targets = format_variables_string(data.domain.class_vars)
81+
metas = format_variables_string(data.domain.metas)
82+
83+
features_missing = missing_values(data.has_missing_attribute()
84+
and data.get_nan_frequency_attribute())
85+
n_features = len(data.domain.variables) + len(data.domain.metas)
86+
name = getattr(data, "name", None)
87+
if name == "untitled":
88+
name = None
89+
basic = f'{len(data)} instance{_plural(len(data))}, ' \
90+
f'{n_features} variable{_plural(n_features)}'
91+
92+
if format == Qt.PlainText:
93+
details = \
94+
(f"'{name}': " if name else "") + basic \
95+
+ f'\nFeatures: {features} {features_missing}' \
96+
+ f'\nTarget: {targets}'
97+
if data.domain.metas:
98+
details += f'\nMetas: {metas}'
99+
else:
61100
details = \
62-
f'{len(data)} instance{_plural(len(data))}, ' \
63-
f'{n_features} variable{_plural(n_features)}\n' \
64-
f'Features: {features} {features_missing}\n' \
65-
f'Target: {targets}\nMetas: {metas}'
66-
return details
101+
_nobr(f"<b>'{escape(name)}'</b>: {basic}" if name else basic) \
102+
+ '<br/>' \
103+
+ _nobr(f'<b>Features</b>: {features} {features_missing}') \
104+
+ '<br/>' \
105+
+ _nobr(f"<b>Target</b>: {targets}")
106+
if data.domain.metas:
107+
details += "<br/>" + _nobr("<b>Metas</b>: {metas}")
108+
return details
67109

68110

69111
def missing_values(value):
70112
if value:
71113
return f'({value*100:.1f}% missing values)'
72114
else:
73-
return '(No missing values)'
115+
return '(no missing values)'
74116

75117

76118
def format_multiple_summaries(data_list, type_io='input'):
@@ -101,3 +143,58 @@ def new_line(text):
101143
details = f'No data on {type_io}.'
102144
full_details.append(details if not name else f'{name}:<br>{details}')
103145
return '<hr>'.join(full_details)
146+
147+
148+
def _name_of(object):
149+
return _nobr(getattr(object, 'name', type(object).__name__))
150+
151+
152+
def _nobr(s):
153+
return f"<nobr>{s}</nobr>"
154+
155+
156+
@summarize.register(Table)
157+
def summarize_(data: Table):
158+
return PartialSummary(
159+
data.approx_len(),
160+
format_summary_details(data, format=Qt.RichText))
161+
162+
163+
@summarize.register(DistMatrix)
164+
def summarize_(matrix: DistMatrix):
165+
n, m = matrix.shape
166+
return PartialSummary(f"{n}×{m}", _nobr(f"{n}×{m} distance matrix"))
167+
168+
169+
@summarize.register(Results)
170+
def summarize_(results: Results):
171+
nmethods, ninstances = results.predicted.shape
172+
summary = f"{nmethods}×{ninstances}"
173+
details = f"{nmethods} method{_plural(nmethods)} " \
174+
f"on {ninstances} test instance{_plural(ninstances)}"
175+
return PartialSummary(summary, _nobr(details))
176+
177+
178+
@summarize.register(AttributeList)
179+
def summarize_(attributes):
180+
n = len(attributes)
181+
if n == 0:
182+
details = "empty list"
183+
elif n <= 3:
184+
details = _nobr(", ".join(var.name for var in attributes))
185+
else:
186+
details = _nobr(", ".join(var.name for var in attributes[:2]) +
187+
f" and {n - 2} others")
188+
return PartialSummary(n, details)
189+
190+
191+
def summarize_by_name(type_, symbol):
192+
@summarize.register(type_)
193+
def summarize_(model: type_):
194+
return PartialSummary(symbol, _name_of(model))
195+
196+
197+
summarize_by_name(Model, "&#9924;" if date.month == 12 else "🄼")
198+
summarize_by_name(Learner, "🄻")
199+
summarize_by_name(Preprocess, "🄿")
200+
summarize_by_name(Scorer, "🅂")

Orange/widgets/widget.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
from Orange.widgets.report import DataReport as Report
1313
from Orange.widgets.utils.signals import AttributeList
1414

15+
# import this to register auto_summary functions
16+
import Orange.widgets.utils.state_summary # pylint: disable=unused-import
1517

1618
__all__ = [
1719
"OWWidget", "Input", "Output", "AttributeList", "Message", "Msg",

0 commit comments

Comments
 (0)