Skip to content

[ENH] OWSilhouettePlot: displays average silhouette #7092

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions Orange/widgets/visualize/owsilhouetteplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@ def __init__(self):
ibox.setFixedWidth(ibox.sizeHint().width())
warning.setVisible(False)

# box displaying the average silhouette score
avg_box = gui.vBox(self.controlArea, "Average Silhouette Score")
self.avg_silhouette_label = gui.widgetLabel(avg_box, "")
self._update_avg_silhouette()

gui.rubber(self.controlArea)

gui.auto_send(self.buttonsArea, self, "auto_commit")
Expand Down Expand Up @@ -292,6 +297,7 @@ def clear(self):
self._clear_scene()
self.Error.clear()
self.Warning.clear()
self._update_avg_silhouette() # Update the average silhouette display

def _clear_scene(self):
# Clear the graphics scene and associated objects
Expand Down Expand Up @@ -340,6 +346,15 @@ def _ensure_matrix(self):
else:
assert False, "invalid state"

def _update_avg_silhouette(self):
# update the average silhouette score
if self._silhouette is not None and len(self._silhouette) > 0:
avg_score = np.mean(self._silhouette)
self.avg_silhouette_label.setText(
f"<b>Silhouette:</b> {avg_score:.4f}")
else:
self.avg_silhouette_label.setText("<b>Silhouette:</b> N/A")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Must it be bold? I don't think we use bold anywhere else (or at least not often).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used bold in Data Info widget, I copied the style from there. But I agree it sticks out, and will correct. Let me work on this in the following days.


def _update(self):
# Update/recompute the effective distances and scores as required.
self._clear_messages()
Expand Down Expand Up @@ -384,6 +399,8 @@ def _update(self):
self.Warning.nan_distances(
count_nandist, s="s" if count_nandist > 1 else "")

self._update_avg_silhouette() # Update the average silhouette display
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment necessary?

I know: copilot and similar tools add heaps and heaps of comments to explain the code, but they often just state the obvious. PEP8 says they're distracting.


def _reset_all(self):
self._mask = None
self._silhouette = None
Expand Down
12 changes: 12 additions & 0 deletions Orange/widgets/visualize/tests/test_owsilhouetteplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,18 @@ def test_migration(self):
self.assertEqual(context.values["cluster_var"], ("cfoo", 101))
self.assertNotIn("annotation_var_idx", values)

def test_average_silhouette_score(self):
data = Table("brown-selected")
self.send_signal(self.widget.Inputs.data, data)
self.assertEqual(self.widget.avg_silhouette_label.text(),
"<b>Silhouette:</b> 0.4692")
self.send_signal(self.widget.Inputs.data, None)
self.assertEqual(self.widget.avg_silhouette_label.text(),
"<b>Silhouette:</b> N/A")
self.send_signal(self.widget.Inputs.data, data)
self.assertEqual(self.widget.avg_silhouette_label.text(),
"<b>Silhouette:</b> 0.4692")


if __name__ == "__main__":
unittest.main()
Loading