Skip to content

Commit 259c257

Browse files
authored
Merge pull request #3574 from janezd/scientific-notation
[ENH] Use %g (including sci notation) if number of decimals is not set
2 parents 0430bae + 8d1c9c4 commit 259c257

File tree

13 files changed

+76
-70
lines changed

13 files changed

+76
-70
lines changed

Orange/classification/simple_tree.py

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -274,35 +274,36 @@ def to_string(self, node=None, level=0):
274274
node = self.node
275275
n = node.contents
276276
if self.type == Classification:
277-
decimals = 1
277+
format_str = format_leaf = format_node = None
278278
else:
279-
decimals = self.domain.class_var.number_of_decimals
279+
format_str = f"({self.domain.class_var.format_str}: %s)"
280+
format_leaf = " --> " + format_str
281+
format_node = "%s " + format_str
280282
if n.children_size == 0:
281283
if self.type == Classification:
282-
node_cont = [round(n.dist[i], decimals)
284+
node_cont = [round(n.dist[i], 1)
283285
for i in range(self.cls_vals)]
284286
index = node_cont.index(max(node_cont))
285287
major_class = self.cls_vars[0].values[index]
286288
return ' --> %s (%s)' % (major_class, node_cont)
287289
else:
288-
node_cont = str(round(n.sum / n.n, decimals)) + ': ' + str(n.n)
289-
return ' --> (%s)' % node_cont
290+
return format_leaf % (n.sum / n.n, n.n)
290291
else:
291292
attr = self.dom_attr[n.split_attr]
292293
node_desc = attr.name
294+
indent = '\n' + ' ' * level
293295
if self.type == Classification:
294-
node_cont = [round(n.dist[i], decimals)
296+
node_cont = [round(n.dist[i], 1)
295297
for i in range(self.cls_vals)]
298+
ret_str = indent + '%s (%s)' % (node_desc, node_cont)
296299
else:
297-
node_cont = str(round(n.sum / n.n, decimals)) + ': ' + str(n.n)
298-
ret_str = '\n' + ' ' * level + '%s (%s)' % (node_desc,
299-
node_cont)
300+
ret_str = indent + format_node % (node_desc, n.sum / n.n, n.n)
300301
for i in range(n.children_size):
301302
if attr.is_continuous:
302303
split = '<=' if i % 2 == 0 else '>'
303-
split += str(round(n.split, attr.number_of_decimals))
304-
ret_str += '\n' + ' ' * level + ': %s' % split
304+
split += attr.format_str % n.split
305+
ret_str += indent + ': %s' % split
305306
else:
306-
ret_str += '\n' + ' ' * level + ': %s' % attr.values[i]
307+
ret_str += indent + ': %s' % attr.values[i]
307308
ret_str += self.to_string(n.children[i], level + 1)
308309
return ret_str

Orange/data/tests/test_variable.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,13 +301,13 @@ def test_decimals(self):
301301

302302
def test_adjust_decimals(self):
303303
a = ContinuousVariable("a")
304-
self.assertEqual(a.str_val(4.654321), "4.654")
304+
self.assertEqual(a.str_val(4.65432), "4.65432")
305305
a.val_from_str_add("5")
306-
self.assertEqual(a.str_val(4.654321), "5")
306+
self.assertEqual(a.str_val(4.65432), "5")
307307
a.val_from_str_add(" 5.12 ")
308-
self.assertEqual(a.str_val(4.654321), "4.65")
308+
self.assertEqual(a.str_val(4.65432), "4.65")
309309
a.val_from_str_add("5.1234")
310-
self.assertEqual(a.str_val(4.654321), "4.6543")
310+
self.assertEqual(a.str_val(4.65432), "4.6543")
311311

312312
def test_colors(self):
313313
a = ContinuousVariable("a")

Orange/data/variable.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -523,15 +523,20 @@ def __init__(self, name="", number_of_decimals=None, compute_value=None, *, spar
523523
"""
524524
super().__init__(name, compute_value, sparse=sparse)
525525
if number_of_decimals is None:
526-
self.number_of_decimals = 3
526+
self._number_of_decimals = 3
527527
self.adjust_decimals = 2
528+
self._format_str = "%g"
528529
else:
529530
self.number_of_decimals = number_of_decimals
530531

531532
@property
532533
def number_of_decimals(self):
533534
return self._number_of_decimals
534535

536+
@property
537+
def format_str(self):
538+
return self._format_str
539+
535540
@property
536541
def colors(self):
537542
if self._colors is None:
@@ -554,7 +559,7 @@ def colors(self, value):
554559
def number_of_decimals(self, x):
555560
self._number_of_decimals = x
556561
self.adjust_decimals = 0
557-
self._out_format = "%.{}f".format(self.number_of_decimals)
562+
self._format_str = "%.{}f".format(self.number_of_decimals)
558563

559564
def to_val(self, s):
560565
"""
@@ -577,7 +582,7 @@ def repr_val(self, val):
577582
"""
578583
if isnan(val):
579584
return "?"
580-
return self._out_format % val
585+
return self._format_str % val
581586

582587
str_val = repr_val
583588

Orange/preprocess/preprocess.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,8 +512,6 @@ def transform(var):
512512
factor = 1 / s
513513
transformed_var = var.copy(
514514
compute_value=transformation.Normalizer(var, c, factor))
515-
if s != 1:
516-
transformed_var.number_of_decimals = 3
517515
return transformed_var
518516

519517
newvars = []

Orange/tests/test_instance.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -229,36 +229,36 @@ def test_set_item(self):
229229
def test_str(self):
230230
domain = self.create_domain(["x", DiscreteVariable("g", values="MF")])
231231
inst = Instance(domain, [42, 0])
232-
self.assertEqual(str(inst), "[42.000, M]")
232+
self.assertEqual(str(inst), "[42, M]")
233233

234234
domain = self.create_domain(["x", DiscreteVariable("g", values="MF")],
235235
[DiscreteVariable("y", values="ABC")])
236236
inst = Instance(domain, [42, "M", "B"])
237-
self.assertEqual(str(inst), "[42.000, M | B]")
237+
self.assertEqual(str(inst), "[42, M | B]")
238238

239239
domain = self.create_domain(["x", DiscreteVariable("g", values="MF")],
240240
[DiscreteVariable("y", values="ABC")],
241241
self.metas)
242242
inst = Instance(domain, [42, "M", "B", "X", 43, "Foo"])
243-
self.assertEqual(str(inst), "[42.000, M | B] {X, 43.000, Foo}")
243+
self.assertEqual(str(inst), "[42, M | B] {X, 43, Foo}")
244244

245245
domain = self.create_domain([],
246246
[DiscreteVariable("y", values="ABC")],
247247
self.metas)
248248
inst = Instance(domain, ["B", "X", 43, "Foo"])
249-
self.assertEqual(str(inst), "[ | B] {X, 43.000, Foo}")
249+
self.assertEqual(str(inst), "[ | B] {X, 43, Foo}")
250250

251251
domain = self.create_domain([],
252252
[],
253253
self.metas)
254254
inst = Instance(domain, ["X", 43, "Foo"])
255-
self.assertEqual(str(inst), "[] {X, 43.000, Foo}")
255+
self.assertEqual(str(inst), "[] {X, 43, Foo}")
256256

257257
domain = self.create_domain(self.attributes)
258258
inst = Instance(domain, range(len(self.attributes)))
259259
self.assertEqual(
260260
str(inst),
261-
"[{}]".format(", ".join("{:.3f}".format(x)
261+
"[{}]".format(", ".join(f"{x:g}"
262262
for x in range(len(self.attributes)))))
263263

264264
for attr in domain.variables:
@@ -271,6 +271,10 @@ def test_str(self):
271271
def test_repr(self):
272272
domain = self.create_domain(self.attributes)
273273
inst = Instance(domain, range(len(self.attributes)))
274+
self.assertEqual(repr(inst), "[0, 1, 2, 3, 4, ...]")
275+
276+
for attr in domain.variables:
277+
attr.number_of_decimals = 3
274278
self.assertEqual(repr(inst), "[0.000, 1.000, 2.000, 3.000, 4.000, ...]")
275279

276280
for attr in domain.variables:

Orange/tests/test_orangetree.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,11 +394,11 @@ def test_methods(self):
394394

395395
def test_print(self):
396396
model = TreeModel(self.data, self.root)
397-
self.assertEqual(model.print_tree(), """ [ 1 42] v1 ≤ 13.000
397+
self.assertEqual(model.print_tree(), """ [ 1 42] v1 ≤ 13
398398
[ 2 42] v2 a
399399
[ 3 42] v2 b
400400
[ 4 42] v2 c
401-
[ 5 42] v1 > 13.000
401+
[ 5 42] v1 > 13
402402
[ 6 42] v3 f
403403
[ 7 42] v3 d or e
404404
""")

Orange/tests/test_simple_tree.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,15 @@ def test_SimpleTree_to_string_regression(self):
140140
reg = lrn(data)
141141
reg_str = reg.to_string()
142142
res = '\n' \
143-
'd1 (20.0: 6.0)\n' \
143+
'd1 (20: 6.0)\n' \
144144
': e\n' \
145-
' c1 (15.0: 4.0)\n' \
145+
' c1 (15: 4.0)\n' \
146146
' : <=2.5\n' \
147-
' c1 (16.667: 3.0)\n' \
148-
' : <=1.5 --> (15.0: 2.0)\n' \
149-
' : >1.5 --> (20.0: 1.0)\n' \
150-
' : >2.5 --> (10.0: 1.0)\n' \
151-
': f --> (30.0: 2.0)'
147+
' c1 (16.6667: 3.0)\n' \
148+
' : <=1.5 --> (15: 2.0)\n' \
149+
' : >1.5 --> (20: 1.0)\n' \
150+
' : >2.5 --> (10: 1.0)\n' \
151+
': f --> (30: 2.0)'
152152
self.assertEqual(reg_str, res)
153153

154154
def test_SimpleTree_to_string_cls_decimals(self):

Orange/tests/test_table.py

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2393,10 +2393,10 @@ def test_transpose_continuous_class(self):
23932393

23942394
att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"),
23952395
ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")]
2396-
att[0].attributes = {"cls": "4.000"}
2397-
att[1].attributes = {"cls": "3.000"}
2398-
att[2].attributes = {"cls": "2.000"}
2399-
att[3].attributes = {"cls": "1.000"}
2396+
att[0].attributes = {"cls": "4"}
2397+
att[1].attributes = {"cls": "3"}
2398+
att[2].attributes = {"cls": "2"}
2399+
att[3].attributes = {"cls": "1"}
24002400
domain = Domain(att, metas=[StringVariable("Feature name")])
24012401
result = Table(domain, np.arange(8).reshape((4, 2)).T,
24022402
metas=np.array(["c1", "c2"])[:, None])
@@ -2419,9 +2419,9 @@ def test_transpose_missing_class(self):
24192419

24202420
att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"),
24212421
ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")]
2422-
att[1].attributes = {"cls": "3.000"}
2423-
att[2].attributes = {"cls": "2.000"}
2424-
att[3].attributes = {"cls": "1.000"}
2422+
att[1].attributes = {"cls": "3"}
2423+
att[2].attributes = {"cls": "2"}
2424+
att[3].attributes = {"cls": "1"}
24252425
domain = Domain(att, metas=[StringVariable("Feature name")])
24262426
result = Table(domain, np.arange(8).reshape((4, 2)).T,
24272427
metas=np.array(["c1", "c2"])[:, None])
@@ -2445,10 +2445,10 @@ def test_transpose_multiple_class(self):
24452445

24462446
att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"),
24472447
ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")]
2448-
att[0].attributes = {"cls1": "0.000", "cls2": "1.000"}
2449-
att[1].attributes = {"cls1": "2.000", "cls2": "3.000"}
2450-
att[2].attributes = {"cls1": "4.000", "cls2": "5.000"}
2451-
att[3].attributes = {"cls1": "6.000", "cls2": "7.000"}
2448+
att[0].attributes = {"cls1": "0", "cls2": "1"}
2449+
att[1].attributes = {"cls1": "2", "cls2": "3"}
2450+
att[2].attributes = {"cls1": "4", "cls2": "5"}
2451+
att[3].attributes = {"cls1": "6", "cls2": "7"}
24522452
domain = Domain(att, metas=[StringVariable("Feature name")])
24532453
result = Table(domain, np.arange(8).reshape((4, 2)).T,
24542454
metas=np.array(["c1", "c2"])[:, None])
@@ -2529,10 +2529,10 @@ def test_transpose_continuous_metas(self):
25292529

25302530
att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"),
25312531
ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")]
2532-
att[0].attributes = {"m1": "0.000"}
2533-
att[1].attributes = {"m1": "1.000"}
2534-
att[2].attributes = {"m1": "0.000"}
2535-
att[3].attributes = {"m1": "1.000"}
2532+
att[0].attributes = {"m1": "0"}
2533+
att[1].attributes = {"m1": "1"}
2534+
att[2].attributes = {"m1": "0"}
2535+
att[3].attributes = {"m1": "1"}
25362536
domain = Domain(att, metas=[StringVariable("Feature name")])
25372537
result = Table(domain, np.arange(8).reshape((4, 2)).T,
25382538
metas=np.array(["c1", "c2"])[:, None])
@@ -2613,10 +2613,10 @@ def test_transpose_class_and_metas(self):
26132613

26142614
att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"),
26152615
ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")]
2616-
att[0].attributes = {"cls": "1.000", "m1": "aa", "m2": "aaa"}
2617-
att[1].attributes = {"cls": "2.000", "m1": "bb", "m2": "bbb"}
2618-
att[2].attributes = {"cls": "3.000", "m1": "cc", "m2": "ccc"}
2619-
att[3].attributes = {"cls": "4.000", "m1": "dd", "m2": "ddd"}
2616+
att[0].attributes = {"cls": "1", "m1": "aa", "m2": "aaa"}
2617+
att[1].attributes = {"cls": "2", "m1": "bb", "m2": "bbb"}
2618+
att[2].attributes = {"cls": "3", "m1": "cc", "m2": "ccc"}
2619+
att[3].attributes = {"cls": "4", "m1": "dd", "m2": "ddd"}
26202620
domain = Domain(att, metas=[StringVariable("Feature name")])
26212621
result = Table(domain, np.arange(8).reshape((4, 2)).T,
26222622
metas=np.array(["c1", "c2"])[:, None])
@@ -2660,8 +2660,8 @@ def test_transpose_attributes_of_attributes_discrete(self):
26602660

26612661
def test_transpose_attributes_of_attributes_continuous(self):
26622662
attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")]
2663-
attrs[0].attributes = {"attr1": "1.100", "attr2": "1.300"}
2664-
attrs[1].attributes = {"attr1": "2.200", "attr2": "2.300"}
2663+
attrs[0].attributes = {"attr1": "1.1", "attr2": "1.3"}
2664+
attrs[1].attributes = {"attr1": "2.2", "attr2": "2.3"}
26652665
domain = Domain(attrs)
26662666
data = Table(domain, np.arange(8).reshape((4, 2)))
26672667

@@ -2683,7 +2683,7 @@ def test_transpose_attributes_of_attributes_continuous(self):
26832683

26842684
# original should not change
26852685
self.assertDictEqual(data.domain.attributes[0].attributes,
2686-
{"attr1": "1.100", "attr2": "1.300"})
2686+
{"attr1": "1.1", "attr2": "1.3"})
26872687

26882688
def test_transpose_attributes_of_attributes_missings(self):
26892689
attrs = [ContinuousVariable("c1"), ContinuousVariable("c2")]
@@ -2724,10 +2724,10 @@ def test_transpose_class_metas_attributes(self):
27242724

27252725
att = [ContinuousVariable("Feature 1"), ContinuousVariable("Feature 2"),
27262726
ContinuousVariable("Feature 3"), ContinuousVariable("Feature 4")]
2727-
att[0].attributes = {"cls": "1.000", "m1": "aa", "m2": "aaa"}
2728-
att[1].attributes = {"cls": "2.000", "m1": "bb", "m2": "bbb"}
2729-
att[2].attributes = {"cls": "3.000", "m1": "cc", "m2": "ccc"}
2730-
att[3].attributes = {"cls": "4.000", "m1": "dd", "m2": "ddd"}
2727+
att[0].attributes = {"cls": "1", "m1": "aa", "m2": "aaa"}
2728+
att[1].attributes = {"cls": "2", "m1": "bb", "m2": "bbb"}
2729+
att[2].attributes = {"cls": "3", "m1": "cc", "m2": "ccc"}
2730+
att[3].attributes = {"cls": "4", "m1": "dd", "m2": "ddd"}
27312731
metas = [StringVariable("Feature name"),
27322732
DiscreteVariable("attr1", values=("a1", "b1")),
27332733
DiscreteVariable("attr2", values=("aa1", "bb1"))]

Orange/widgets/evaluate/owpredictions.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -430,8 +430,7 @@ def _setup_delegate_discrete(self, delegate):
430430
return delegate
431431

432432
def _setup_delegate_continuous(self, delegate):
433-
delegate.setFormat(
434-
"{{value:.{}f}}".format(self.class_var.number_of_decimals))
433+
delegate.setFormat("{{value:{}}}".format(self.class_var.format_str[1:]))
435434

436435
def _update_spliter(self):
437436
if self.data is None:

Orange/widgets/model/owlinearregression.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,7 @@ def update_model(self):
134134
coef_table = None
135135
if self.model is not None:
136136
domain = Domain(
137-
[ContinuousVariable("coef", number_of_decimals=7)],
138-
metas=[StringVariable("name")])
137+
[ContinuousVariable("coef")], metas=[StringVariable("name")])
139138
coefs = [self.model.intercept] + list(self.model.coefficients)
140139
names = ["intercept"] + \
141140
[attr.name for attr in self.model.domain.attributes]

0 commit comments

Comments
 (0)