diff --git a/tests/unit_tests/plugin_tests/test_tornado_functions.py b/tests/unit_tests/plugin_tests/test_tornado_functions.py
new file mode 100644
index 000000000..9b7dcf98b
--- /dev/null
+++ b/tests/unit_tests/plugin_tests/test_tornado_functions.py
@@ -0,0 +1,12 @@
+import webviz_subsurface._private_plugins.tornado_plot as tornado_plot
+
+
+def test_printable_int_list():
+ assert (
+ tornado_plot.printable_int_list([1, 2, 5, 6, 9, 8, 19]) == "1-2, 5-6, 8-9, 19"
+ )
+ assert tornado_plot.printable_int_list([5, 3, 4, 0]) == "0, 3-5"
+ assert tornado_plot.printable_int_list([0, 1, 2, 3, 6]) == "0-3, 6"
+ assert tornado_plot.printable_int_list([]) == "None"
+ assert tornado_plot.printable_int_list(None) == "None"
+ assert tornado_plot.printable_int_list([5]) == "5"
diff --git a/webviz_subsurface/_private_plugins/tornado_plot.py b/webviz_subsurface/_private_plugins/tornado_plot.py
index 8626b865f..8138bf461 100644
--- a/webviz_subsurface/_private_plugins/tornado_plot.py
+++ b/webviz_subsurface/_private_plugins/tornado_plot.py
@@ -1,7 +1,8 @@
from uuid import uuid4
import json
-import pandas as pd
+from typing import List, Optional
+import pandas as pd
import dash
from dash.dependencies import Input, Output
from dash.exceptions import PreventUpdate
@@ -355,10 +356,10 @@ def tornado_plot(
p10 = case_df["VALUE"].quantile(0.90)
# Extract list of realizations with values less then reference avg (low)
- low_reals = list(case_df.loc[case_df["VALUE"] <= ref_avg]["REAL"])
+ low_reals = list(map(int, case_df.loc[case_df["VALUE"] <= ref_avg]["REAL"]))
# Extract list of realizations with values higher then reference avg (high)
- high_reals = list(case_df.loc[case_df["VALUE"] > ref_avg]["REAL"])
+ high_reals = list(map(int, case_df.loc[case_df["VALUE"] > ref_avg]["REAL"]))
arr.append(
{
@@ -430,7 +431,7 @@ def tornado_plot(
f"
Case: {label}
True Value: "
f"{si_prefixed(val, number_format, unit, spaced, locked_si_prefix)}"
f"
Realizations: "
- f"{int(min(reals)) if reals else None}-{int(max(reals)) if reals else None}"
+ f"{printable_int_list(reals)}"
for x, label, val, reals in zip(
df["low"], df["low_label"], df["true_low"], df["low_reals"]
)
@@ -450,7 +451,7 @@ def tornado_plot(
f"
Case: {label}
True Value: "
f"{si_prefixed(val, number_format, unit, spaced, locked_si_prefix)}"
f"
Realizations: "
- f"{int(min(reals)) if reals else None}-{int(max(reals)) if reals else None}"
+ f"{printable_int_list(reals)}"
for x, label, val, reals in zip(
df["high"], df["high_label"], df["true_high"], df["high_reals"]
)
@@ -574,3 +575,31 @@ def calc_low_x(low, high):
base = min(0, high)
return low - base
return 0
+
+
+def printable_int_list(integer_list: Optional[List[int]]):
+ """Creates a string out of a list of integers.
+ The string gives a range x-y if all the integers between and
+ including x and y are in the list, otherwise separated by commas.
+ Example: the list [0, 1, 2, 4, 5, 8, 10] becomes '0-2, 4-5, 8, 10'
+ If the input is `None` or the list is empty, the string 'None' is returned.
+ """
+ if not integer_list:
+ return "None"
+
+ sorted_list = sorted(integer_list)
+ prev_number = sorted_list[0]
+ string = str(prev_number)
+
+ for next_number in sorted_list[1:]:
+ if next_number > prev_number + 1:
+ string += (
+ f"{prev_number}" if string.endswith("-") else ""
+ ) + f", {next_number}"
+ elif not string.endswith("-"):
+ string += "-"
+ prev_number = next_number
+
+ if not string.endswith(f", {prev_number}") and string != str(prev_number):
+ string += str(prev_number)
+ return string