coralnet-toolbox 0.0.68__py2.py3-none-any.whl → 0.0.69__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- coralnet_toolbox/Explorer/QtDataItem.py +55 -16
- coralnet_toolbox/Explorer/QtExplorer.py +1151 -336
- coralnet_toolbox/Explorer/QtFeatureStore.py +176 -0
- coralnet_toolbox/Explorer/QtSettingsWidgets.py +207 -24
- coralnet_toolbox/QtEventFilter.py +18 -17
- coralnet_toolbox/QtMainWindow.py +59 -7
- coralnet_toolbox/__init__.py +1 -1
- {coralnet_toolbox-0.0.68.dist-info → coralnet_toolbox-0.0.69.dist-info}/METADATA +4 -2
- {coralnet_toolbox-0.0.68.dist-info → coralnet_toolbox-0.0.69.dist-info}/RECORD +13 -12
- {coralnet_toolbox-0.0.68.dist-info → coralnet_toolbox-0.0.69.dist-info}/WHEEL +0 -0
- {coralnet_toolbox-0.0.68.dist-info → coralnet_toolbox-0.0.69.dist-info}/entry_points.txt +0 -0
- {coralnet_toolbox-0.0.68.dist-info → coralnet_toolbox-0.0.69.dist-info}/licenses/LICENSE.txt +0 -0
- {coralnet_toolbox-0.0.68.dist-info → coralnet_toolbox-0.0.69.dist-info}/top_level.txt +0 -0
@@ -2,6 +2,8 @@ import warnings
|
|
2
2
|
|
3
3
|
import os
|
4
4
|
|
5
|
+
import numpy as np
|
6
|
+
|
5
7
|
from PyQt5.QtCore import Qt, QTimer
|
6
8
|
from PyQt5.QtGui import QPen, QColor, QPainter
|
7
9
|
from PyQt5.QtWidgets import QGraphicsEllipseItem, QStyle, QVBoxLayout, QLabel, QWidget, QGraphicsItem
|
@@ -54,6 +56,12 @@ class EmbeddingPointItem(QGraphicsEllipseItem):
|
|
54
56
|
|
55
57
|
# Set the position of the point based on the data item's embedding coordinates
|
56
58
|
self.setPos(self.data_item.embedding_x, self.data_item.embedding_y)
|
59
|
+
# Set the tooltip with detailed information
|
60
|
+
self.setToolTip(self.data_item.get_tooltip_text())
|
61
|
+
|
62
|
+
def update_tooltip(self):
|
63
|
+
"""Updates the tooltip by fetching the latest text from the data item."""
|
64
|
+
self.setToolTip(self.data_item.get_tooltip_text())
|
57
65
|
|
58
66
|
def paint(self, painter, option, widget):
|
59
67
|
"""
|
@@ -104,6 +112,10 @@ class AnnotationImageWidget(QWidget):
|
|
104
112
|
self.image_label.setScaledContents(True)
|
105
113
|
self.image_label.setStyleSheet("border: none;")
|
106
114
|
layout.addWidget(self.image_label)
|
115
|
+
|
116
|
+
def update_tooltip(self):
|
117
|
+
"""Updates the tooltip by fetching the latest text from the data item."""
|
118
|
+
self.setToolTip(self.data_item.get_tooltip_text())
|
107
119
|
|
108
120
|
def load_and_set_image(self):
|
109
121
|
"""Load image, calculate its aspect ratio, and set the widget's initial size."""
|
@@ -124,7 +136,10 @@ class AnnotationImageWidget(QWidget):
|
|
124
136
|
self.image_label.setText("Error\nLoading Image")
|
125
137
|
self.pixmap = None
|
126
138
|
self.aspect_ratio = 1.0
|
139
|
+
|
127
140
|
self.update_height(self.widget_height)
|
141
|
+
# Set the initial tooltip
|
142
|
+
self.update_tooltip()
|
128
143
|
|
129
144
|
def update_height(self, new_height):
|
130
145
|
"""Updates the widget's height and rescales its width and content accordingly."""
|
@@ -204,8 +219,12 @@ class AnnotationImageWidget(QWidget):
|
|
204
219
|
# The viewer is the controller and will decide how to change the selection state
|
205
220
|
self.annotation_viewer.handle_annotation_selection(self, event)
|
206
221
|
elif event.button() == Qt.RightButton:
|
207
|
-
|
208
|
-
|
222
|
+
if self.annotation_viewer and hasattr(self.annotation_viewer, 'handle_annotation_context_menu'):
|
223
|
+
self.annotation_viewer.handle_annotation_context_menu(self, event)
|
224
|
+
event.accept()
|
225
|
+
return
|
226
|
+
else:
|
227
|
+
event.ignore()
|
209
228
|
super().mousePressEvent(event)
|
210
229
|
|
211
230
|
|
@@ -218,14 +237,20 @@ class AnnotationDataItem:
|
|
218
237
|
|
219
238
|
def __init__(self, annotation, embedding_x=None, embedding_y=None, embedding_id=None):
|
220
239
|
self.annotation = annotation
|
240
|
+
|
221
241
|
self.embedding_x = embedding_x if embedding_x is not None else 0.0
|
222
242
|
self.embedding_y = embedding_y if embedding_y is not None else 0.0
|
223
243
|
self.embedding_id = embedding_id if embedding_id is not None else 0
|
244
|
+
|
224
245
|
self._is_selected = False
|
225
246
|
self._preview_label = None
|
226
247
|
self._original_label = annotation.label
|
227
|
-
|
228
|
-
|
248
|
+
|
249
|
+
# To store pre-formatted top-k prediction details
|
250
|
+
self.prediction_details = None
|
251
|
+
# To store prediction probabilities for sorting
|
252
|
+
self.prediction_probabilities = None
|
253
|
+
|
229
254
|
@property
|
230
255
|
def effective_label(self):
|
231
256
|
"""Get the current effective label (preview if it exists, otherwise original)."""
|
@@ -257,18 +282,6 @@ class AnnotationDataItem:
|
|
257
282
|
"""Check if this annotation has a temporary preview label assigned."""
|
258
283
|
return self._preview_label is not None
|
259
284
|
|
260
|
-
def mark_for_deletion(self):
|
261
|
-
"""Mark this annotation for deletion."""
|
262
|
-
self._marked_for_deletion = True
|
263
|
-
|
264
|
-
def unmark_for_deletion(self):
|
265
|
-
"""Unmark this annotation for deletion."""
|
266
|
-
self._marked_for_deletion = False
|
267
|
-
|
268
|
-
def is_marked_for_deletion(self):
|
269
|
-
"""Check if this annotation is marked for deletion."""
|
270
|
-
return self._marked_for_deletion
|
271
|
-
|
272
285
|
def apply_preview_permanently(self):
|
273
286
|
"""Apply the preview label permanently to the underlying annotation object."""
|
274
287
|
if self._preview_label:
|
@@ -290,9 +303,35 @@ class AnnotationDataItem:
|
|
290
303
|
'embedding_id': self.embedding_id,
|
291
304
|
'color': self.effective_color
|
292
305
|
}
|
306
|
+
|
307
|
+
def get_tooltip_text(self):
|
308
|
+
"""
|
309
|
+
Generates a rich HTML-formatted tooltip with all relevant information.
|
310
|
+
"""
|
311
|
+
info = self.get_display_info()
|
312
|
+
|
313
|
+
tooltip_parts = [
|
314
|
+
f"<b>ID:</b> {info['id']}",
|
315
|
+
f"<b>Image:</b> {info['image']}",
|
316
|
+
f"<b>Label:</b> {info['label']}",
|
317
|
+
f"<b>Type:</b> {info['type']}"
|
318
|
+
]
|
319
|
+
|
320
|
+
# Add prediction details if they exist
|
321
|
+
if self.prediction_details:
|
322
|
+
tooltip_parts.append(f"<hr>{self.prediction_details}")
|
323
|
+
|
324
|
+
return "<br>".join(tooltip_parts)
|
293
325
|
|
294
326
|
def get_effective_confidence(self):
|
295
327
|
"""Get the effective confidence value."""
|
328
|
+
# First check if prediction probabilities are available from model predictions
|
329
|
+
if hasattr(self, 'prediction_probabilities') and self.prediction_probabilities is not None:
|
330
|
+
if len(self.prediction_probabilities) > 0:
|
331
|
+
# Use the maximum probability for confidence sorting
|
332
|
+
return float(np.max(self.prediction_probabilities))
|
333
|
+
|
334
|
+
# Fallback to existing confidence values
|
296
335
|
if self.annotation.verified and hasattr(self.annotation, 'user_confidence') and self.annotation.user_confidence:
|
297
336
|
return list(self.annotation.user_confidence.values())[0]
|
298
337
|
elif hasattr(self.annotation, 'machine_confidence') and self.annotation.machine_confidence:
|