Skip to content

Commit 4b609d5

Browse files
committed
Restyle realization status indicators
The pastel fills with a pie-chart overlay and a "finished / total" caption are hard to scan at larger realization counts, and the pie competes with the status fill for the same shape. Replace it with a status dot plus a progress ring drawn only while running, dropping the caption the ring now conveys. Shrink the cells so more of the ensemble fits on screen.
1 parent 6557b68 commit 4b609d5

4 files changed

Lines changed: 95 additions & 61 deletions

File tree

src/ert/ensemble_evaluator/state.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
from typing import Final
22

3-
COLOR_FAILED: Final = (255, 200, 200)
4-
COLOR_FINISHED: Final = (127, 201, 127)
5-
COLOR_PENDING: Final = (190, 174, 212)
6-
COLOR_RUNNING: Final = (255, 255, 153)
7-
COLOR_UNKNOWN: Final = (128, 128, 128)
8-
COLOR_WAITING: Final = (164, 200, 255)
9-
COLOR_CANCELLED: Final = (235, 242, 246)
3+
COLOR_QUEUED: Final = (183, 191, 199)
4+
COLOR_FAILED: Final = (207, 34, 46)
5+
COLOR_FINISHED: Final = (45, 164, 78)
6+
COLOR_PENDING: Final = COLOR_QUEUED
7+
COLOR_RUNNING: Final = (214, 178, 42)
8+
COLOR_UNKNOWN: Final = (140, 149, 159)
9+
COLOR_WAITING: Final = COLOR_QUEUED
10+
COLOR_CANCELLED: Final = (234, 238, 242)
1011
COLOR_WARNING: Final = (255, 103, 0)
1112

1213
ENSEMBLE_STATE_CANCELLED: Final = "Cancelled"

src/ert/gui/experiments/view/progress_widget.py

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
QVBoxLayout,
1212
)
1313

14-
from ert.ensemble_evaluator.state import ENSEMBLE_STATE_FAILED, REAL_STATE_TO_COLOR
14+
from ert.ensemble_evaluator.state import (
15+
ENSEMBLE_STATE_FAILED,
16+
REAL_STATE_TO_COLOR,
17+
REALIZATION_STATE_WAITING,
18+
)
1519

1620

1721
class ProgressWidget(QFrame):
@@ -21,7 +25,7 @@ def __init__(self) -> None:
2125

2226
self._vertical_layout = QVBoxLayout(self)
2327
self._vertical_layout.setContentsMargins(0, 0, 0, 0)
24-
self._vertical_layout.setSpacing(0)
28+
self._vertical_layout.setSpacing(2)
2529
self.setLayout(self._vertical_layout)
2630

2731
self._waiting_progress_bar = QProgressBar(self)
@@ -39,36 +43,47 @@ def __init__(self) -> None:
3943

4044
self._legend_frame = QFrame(self)
4145
self._vertical_layout.addWidget(self._legend_frame)
42-
self._legend_frame.setFixedHeight(30)
46+
self._legend_frame.setFixedHeight(24)
4347
self._horizontal_legend_layout = QHBoxLayout(self._legend_frame)
4448
self._horizontal_legend_layout.setContentsMargins(0, 0, 0, 0)
45-
self._horizontal_legend_layout.setSpacing(0)
49+
self._horizontal_legend_layout.setSpacing(6)
4650

4751
self._status: dict[str, int] = {}
4852
self._realization_count = 0
4953
self._progress_label_map: dict[str, QLabel] = {}
5054
self._legend_map_text = {}
51-
5255
for state, color in REAL_STATE_TO_COLOR.items():
56+
color_name = QColor(*color).name()
57+
5358
label = QLabel(self)
5459
label.setVisible(False)
5560
label.setObjectName(f"progress_{state}")
56-
label.setStyleSheet(f"background-color : {QColor(*color).name()}")
61+
label.setStyleSheet(f"background-color : {color_name}")
5762
self._progress_label_map[state] = label
5863
self._horizontal_layout.addWidget(label)
5964

60-
label = QLabel(self)
61-
label.setFixedSize(20, 20)
62-
label.setStyleSheet(
63-
f"background-color : {QColor(*color).name()}; border: 1px solid black;"
64-
)
65-
self._horizontal_legend_layout.addWidget(label)
65+
if state == REALIZATION_STATE_WAITING:
66+
marker_style = (
67+
"background-color: transparent;"
68+
"border-radius: 7px;"
69+
f"border: 2px solid {color_name};"
70+
)
71+
else:
72+
marker_style = f"background-color: {color_name};border-radius: 7px;"
73+
74+
legend_marker = QLabel(self)
75+
legend_marker.setFixedSize(14, 14)
76+
legend_marker.setStyleSheet(marker_style)
77+
self._horizontal_legend_layout.addWidget(legend_marker)
6678

6779
label = QLabel(self)
6880
label.setObjectName(f"progress_label_text_{state}")
69-
label.setText(f" {state} ({0}/{0})")
81+
label.setText(f"{state} ({0}/{0})")
7082
self._legend_map_text[state] = label
7183
self._horizontal_legend_layout.addWidget(label)
84+
self._horizontal_legend_layout.addSpacing(16)
85+
86+
self._horizontal_legend_layout.addStretch()
7287

7388
def repaint_components(self) -> None:
7489
if self._realization_count > 0:
@@ -83,7 +98,7 @@ def repaint_components(self) -> None:
8398

8499
for state, label in self._legend_map_text.items():
85100
label.setText(
86-
f" {state} ({self._status.get(state, 0)}/{self._realization_count})"
101+
f"{state} ({self._status.get(state, 0)}/{self._realization_count})"
87102
)
88103

89104
def stop_waiting_progress_bar(self) -> None:

src/ert/gui/experiments/view/realization.py

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
QModelIndex,
88
QObject,
99
QPoint,
10+
QRect,
1011
QSize,
1112
Qt,
1213
)
@@ -23,12 +24,14 @@
2324
QWidget,
2425
)
2526

27+
from ert.ensemble_evaluator import state
2628
from ert.gui.model.real_list import RealListModel
2729
from ert.gui.model.snapshot import (
2830
CallbackStatusMessageRole,
2931
FMStepColorHint,
3032
MemoryUsageRole,
3133
RealIens,
34+
StatusRole,
3235
)
3336
from ert.shared.status.utils import byte_with_unit
3437

@@ -40,7 +43,7 @@ def __init__(self, it: int, parent: QWidget | None = None) -> None:
4043
super().__init__(parent)
4144

4245
self._iter = it
43-
self._delegate_size = QSize(90, 90)
46+
self._delegate_size = QSize(70, 70)
4447

4548
self._real_view = QListView(self)
4649
self._real_view.setViewMode(QListView.ViewMode.IconMode)
@@ -95,66 +98,81 @@ def refresh_current_selection(self) -> None:
9598

9699

97100
class RealizationDelegate(QStyledItemDelegate):
101+
_DOT_DIAMETER = 32
102+
_ARC_MARGIN = 4
103+
_ARC_WIDTH = 5
104+
98105
def __init__(self, size: QSize, parent: QObject) -> None:
99106
super().__init__(parent)
100107
self._size = size
101108
parent.installEventFilter(self)
102-
self.adjustment_point_for_job_rect_margin = QPoint(-20, -20)
103-
self._color_black = QColor(0, 0, 0, 180)
104-
self._color_progress = QColor(50, 173, 230, 200)
105-
self._color_lightgray = QColor("LightGray").lighter(120)
106-
self._pen_black = QPen(self._color_black, 2, Qt.PenStyle.SolidLine)
109+
self.adjustment_point_for_job_rect_margin = QPoint(-12, -12)
110+
self._color_track = QColor(0, 0, 0, 35)
111+
self._pen_outline = QPen(QColor(0, 0, 0, 45), 1, Qt.PenStyle.SolidLine)
107112

108113
@override
109114
def paint(
110115
self, painter: QPainter | None, option: QStyleOptionViewItem, index: QModelIndex
111116
) -> None:
112117
if painter is None:
113118
return
114-
text = index.data(RealIens)
115-
selected_color, finished_count, total_count = tuple(index.data(FMStepColorHint))
119+
realization_label = index.data(RealIens)
120+
status = index.data(StatusRole)
121+
status_color, completed_step_count, total_step_count = tuple(
122+
index.data(FMStepColorHint)
123+
)
116124

117125
painter.save()
118126
painter.setRenderHint(QPainter.RenderHint.TextAntialiasing, True)
119127
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
120128

121-
percentage_done = (
122-
100 if total_count < 1 else int((finished_count * 100.0) / total_count)
123-
)
124-
125-
painter.setPen(self._pen_black)
126-
adjusted_rect = option.rect.adjusted(2, 2, -2, -2)
127-
128-
painter.setBrush(
129-
self._color_progress if percentage_done == 100 else self._color_lightgray
129+
if option.state & QStyle.StateFlag.State_Selected:
130+
highlight = QColor(option.palette.color(QPalette.ColorRole.Highlight))
131+
highlight.setAlpha(60)
132+
painter.setPen(Qt.PenStyle.NoPen)
133+
painter.setBrush(highlight)
134+
painter.drawRoundedRect(option.rect.adjusted(2, 2, -2, -2), 6, 6)
135+
136+
status_dot_rect = QRect(
137+
option.rect.center().x() - self._DOT_DIAMETER // 2,
138+
option.rect.top() + 8,
139+
self._DOT_DIAMETER,
140+
self._DOT_DIAMETER,
130141
)
131-
painter.drawEllipse(adjusted_rect)
132-
133-
if 0 < percentage_done < 100:
134-
painter.setBrush(self._color_progress)
135-
painter.drawPie(adjusted_rect, 1440, -int(percentage_done * 57.6))
136142

137-
if option.state & QStyle.StateFlag.State_Selected:
138-
factor: int = (
139-
125
140-
if selected_color.lighter(125).getRgb() != (255, 255, 255, 255)
141-
else 110
143+
if status == state.REALIZATION_STATE_RUNNING and total_step_count > 0:
144+
progress_ring_rect = status_dot_rect.adjusted(
145+
-self._ARC_MARGIN,
146+
-self._ARC_MARGIN,
147+
self._ARC_MARGIN,
148+
self._ARC_MARGIN,
149+
)
150+
painter.setBrush(Qt.BrushStyle.NoBrush)
151+
painter.setPen(QPen(self._color_track, self._ARC_WIDTH))
152+
painter.drawEllipse(progress_ring_rect)
153+
progress_pen = QPen(status_color, self._ARC_WIDTH)
154+
progress_pen.setCapStyle(Qt.PenCapStyle.RoundCap)
155+
painter.setPen(progress_pen)
156+
painter.drawArc(
157+
progress_ring_rect,
158+
90 * 16,
159+
-int(360 * 16 * completed_step_count / total_step_count),
142160
)
143-
selected_color = selected_color.lighter(factor)
144-
145-
painter.setBrush(selected_color)
146-
adjusted_rect = option.rect.adjusted(7, 7, -7, -7)
147-
painter.drawEllipse(adjusted_rect)
148161

149-
font = painter.font()
150-
font.setBold(True)
151-
painter.setFont(font)
162+
painter.setPen(self._pen_outline)
163+
if status == state.REALIZATION_STATE_WAITING:
164+
painter.setBrush(Qt.BrushStyle.NoBrush)
165+
painter.setPen(QPen(status_color, 2))
166+
painter.drawEllipse(status_dot_rect.adjusted(1, 1, -1, -1))
167+
else:
168+
painter.setBrush(status_color)
169+
painter.drawEllipse(status_dot_rect)
152170

153-
adj_rect = option.rect.adjusted(0, 20, 0, 0)
154-
painter.drawText(adj_rect, Qt.AlignmentFlag.AlignHCenter, text)
155-
adj_rect = option.rect.adjusted(0, 45, 0, 0)
171+
painter.setPen(option.palette.color(QPalette.ColorRole.Text))
156172
painter.drawText(
157-
adj_rect, Qt.AlignmentFlag.AlignHCenter, f"{finished_count} / {total_count}"
173+
option.rect.adjusted(0, self._DOT_DIAMETER + 14, 0, 0),
174+
Qt.AlignmentFlag.AlignHCenter,
175+
realization_label,
158176
)
159177

160178
painter.restore()

tests/ert/unit_tests/gui/experiments/view/test_legend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def test_marker_label_text_correct(qtbot, status: dict[str, int]):
3131

3232
assert label_marker
3333
count = status.get(state, 0)
34-
assert f" {state} ({count}/{realization_count})" in label_marker.text()
34+
assert f"{state} ({count}/{realization_count})" in label_marker.text()
3535

3636

3737
@given(

0 commit comments

Comments
 (0)