From 5dace185d11dfb1bc73c2e75a180f4bd552a603d Mon Sep 17 00:00:00 2001
From: PrimozGodec
Date: Wed, 26 Jul 2023 11:28:19 +0200
Subject: [PATCH 1/5] Explainer - fix deprecations
---
orangecontrib/explain/explainer.py | 2 +-
orangecontrib/explain/tests/test_explainer.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/orangecontrib/explain/explainer.py b/orangecontrib/explain/explainer.py
index dcaa155..568ff51 100644
--- a/orangecontrib/explain/explainer.py
+++ b/orangecontrib/explain/explainer.py
@@ -596,7 +596,7 @@ def get_instance_ordering(
NotImplementedError if unknown order_by.
"""
if isinstance(order_by, Variable):
- x_data = data.get_column_view(order_by)[0]
+ x_data = data.get_column(order_by)
clust_ord = np.argsort(hclust_ordering(shap_values))
return np.lexsort([clust_ord, x_data])
elif order_by == ORIGINAL_ORDER:
diff --git a/orangecontrib/explain/tests/test_explainer.py b/orangecontrib/explain/tests/test_explainer.py
index 6dbe84b..77c8700 100644
--- a/orangecontrib/explain/tests/test_explainer.py
+++ b/orangecontrib/explain/tests/test_explainer.py
@@ -276,7 +276,7 @@ def test_all_regressors(self):
if learner == CurveFitLearner:
attr = self.housing.domain.attributes
learner = CurveFitLearner(
- lambda x, a: np.sum(x[:, i] for i in range(len(attr))),
+ lambda x, a: sum(x[:, i] for i in range(len(attr))),
[], [a.name for a in self.housing.domain.attributes]
)
else:
From e6dcec23ab2fd37498c2886600f40831d05574cc Mon Sep 17 00:00:00 2001
From: PrimozGodec
Date: Wed, 26 Jul 2023 11:36:56 +0200
Subject: [PATCH 2/5] owexplainfeaturebase - use deferred commit
---
orangecontrib/explain/widgets/owexplainfeaturebase.py | 5 +++--
orangecontrib/explain/widgets/owexplainmodel.py | 2 +-
orangecontrib/explain/widgets/owpermutationimportance.py | 2 +-
3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/orangecontrib/explain/widgets/owexplainfeaturebase.py b/orangecontrib/explain/widgets/owexplainfeaturebase.py
index 85abc83..eb68624 100644
--- a/orangecontrib/explain/widgets/owexplainfeaturebase.py
+++ b/orangecontrib/explain/widgets/owexplainfeaturebase.py
@@ -549,16 +549,17 @@ def _update_plot(self):
def _clear_selection(self):
if self.selection:
self.selection = ()
- self.commit()
+ self.commit.deferred()
def update_selection(self, *_):
raise NotImplementedError
def select_pending(self, pending_selection: Tuple):
self.__pending_selection = pending_selection
- self.unconditional_commit()
+ self.commit.now()
# Outputs
+ @gui.deferred
def commit(self):
selected_data = self.get_selected_data()
if not selected_data:
diff --git a/orangecontrib/explain/widgets/owexplainmodel.py b/orangecontrib/explain/widgets/owexplainmodel.py
index 7b7316f..a3a6e3e 100644
--- a/orangecontrib/explain/widgets/owexplainmodel.py
+++ b/orangecontrib/explain/widgets/owexplainmodel.py
@@ -421,7 +421,7 @@ def update_selection(self, min_val: float, max_val: float, attr_name: str):
if not self.selection and not any(mask):
return
self.selection = (attr_name, list(np.flatnonzero(mask)))
- self.commit()
+ self.commit.deferred()
def select_pending(self, pending_selection: Tuple):
if not pending_selection or not pending_selection[1] \
diff --git a/orangecontrib/explain/widgets/owpermutationimportance.py b/orangecontrib/explain/widgets/owpermutationimportance.py
index 2484530..c77b4c5 100644
--- a/orangecontrib/explain/widgets/owpermutationimportance.py
+++ b/orangecontrib/explain/widgets/owpermutationimportance.py
@@ -315,7 +315,7 @@ def update_selection(self, attr_names: Set[str]):
return
assert self.results is not None
self.selection = tuple(attr_names)
- self.commit()
+ self.commit.deferred()
def select_pending(self, pending_selection: Tuple):
if not pending_selection or self.results is None:
From 3d6fd373c5aeb6deead78e8eda668c0e6f0a4cfd Mon Sep 17 00:00:00 2001
From: PrimozGodec
Date: Wed, 26 Jul 2023 11:44:18 +0200
Subject: [PATCH 3/5] owexplainpredictions - use deferred commit
---
orangecontrib/explain/widgets/owexplainpredictions.py | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/orangecontrib/explain/widgets/owexplainpredictions.py b/orangecontrib/explain/widgets/owexplainpredictions.py
index b77c57b..a50730f 100644
--- a/orangecontrib/explain/widgets/owexplainpredictions.py
+++ b/orangecontrib/explain/widgets/owexplainpredictions.py
@@ -587,7 +587,7 @@ def _add_plot(self):
def __on_selection_changed(self, selection: List[Tuple[float, float]]):
self.selection_ranges = selection
- self.commit()
+ self.commit.deferred()
def _add_controls(self):
box = gui.vBox(self.controlArea, "Target class")
@@ -624,12 +624,12 @@ def _add_controls(self):
def __on_target_changed(self):
self.selection_ranges = []
self.setup_plot()
- self.commit()
+ self.commit.deferred()
def __on_order_changed(self):
self.selection_ranges = []
self.setup_plot()
- self.commit()
+ self.commit.deferred()
def __on_annot_changed(self):
if not self.__results or not self.data:
@@ -717,7 +717,7 @@ def _setup_controls(self):
def handleNewSignals(self):
self.clear()
self.start(run, self.data, self.background_data, self.model)
- self.commit()
+ self.commit.deferred()
def clear(self):
self.__results = None
@@ -815,6 +815,7 @@ def apply_selection(self):
self.__on_selection_changed(selection_ranges)
self.__pending_selection = []
+ @gui.deferred
def commit(self):
selected = None
selected_indices = []
From 61705eeb95559e40694403c31d5106c9244bacb9 Mon Sep 17 00:00:00 2001
From: PrimozGodec
Date: Wed, 26 Jul 2023 12:12:51 +0200
Subject: [PATCH 4/5] ICE - replace ListViewSearch with ListViewFilter
---
orangecontrib/explain/widgets/owice.py | 25 ++++++++-----------
.../explain/widgets/tests/test_owice.py | 17 ++++++++-----
2 files changed, 22 insertions(+), 20 deletions(-)
diff --git a/orangecontrib/explain/widgets/owice.py b/orangecontrib/explain/widgets/owice.py
index 26f75ac..3764515 100644
--- a/orangecontrib/explain/widgets/owice.py
+++ b/orangecontrib/explain/widgets/owice.py
@@ -5,7 +5,7 @@
import numpy as np
from AnyQt.QtCore import Qt, QSortFilterProxyModel, QSize, QModelIndex, \
- QItemSelection, QPointF, Signal, QLineF
+ QPointF, Signal, QLineF
from AnyQt.QtGui import QColor
from AnyQt.QtWidgets import QComboBox, QSizePolicy, QGraphicsSceneHelpEvent, \
QToolTip, QGraphicsLineItem, QApplication
@@ -13,7 +13,7 @@
import pyqtgraph as pg
from orangecanvas.gui.utils import disconnected
-from orangewidget.utils.listview import ListViewSearch
+from orangewidget.utils.listview import ListViewFilter
from Orange.base import Model
from Orange.data import Table, ContinuousVariable, Variable, \
@@ -261,7 +261,7 @@ def __on_mouse_moved(self, point: QPointF):
)
# points
- x_data = self.__data.get_column_view(self.__feature)[0][indices]
+ x_data = self.__data.get_column(self.__feature)[indices]
n_dec = self.__feature.number_of_decimals
y_data = []
for i, x in zip(indices, x_data):
@@ -537,7 +537,7 @@ def __init__(self):
self.domain: Optional[Domain] = None
self.graph: ICEPlot = None
self._target_combo: QComboBox = None
- self._features_view: ListViewSearch = None
+ self._features_view: ListViewFilter = None
self._features_model: VariableListModel = None
self._color_model: DomainModel = None
@@ -571,10 +571,10 @@ def _add_controls(self):
box = gui.vBox(self.controlArea, "Feature")
self._features_model = VariableListModel()
sorted_model = SortProxyModel(sortRole=Qt.UserRole)
- sorted_model.setSourceModel(self._features_model)
sorted_model.sort(0)
- self._features_view = ListViewSearch()
- self._features_view.setModel(sorted_model)
+ self._features_view = ListViewFilter(
+ model=self._features_model, proxy=sorted_model
+ )
self._features_view.setMinimumSize(QSize(30, 100))
self._features_view.setSizePolicy(QSizePolicy.Expanding,
QSizePolicy.Expanding)
@@ -600,12 +600,9 @@ def __on_target_changed(self):
self._apply_feature_sorting()
self.__on_parameter_changed()
- def __on_feature_changed(self, selection: QItemSelection):
- if not selection:
- return
-
- self.feature = selection.indexes()[0].data(gui.TableVariable)
- self._apply_feature_sorting()
+ def __on_feature_changed(self):
+ selection = self._features_view.selectionModel().selectedIndexes()
+ self.feature = selection[0].data(gui.TableVariable) if selection else None
self._run()
def __on_order_changed(self):
@@ -788,7 +785,7 @@ def setup_plot(self):
color_labels = None
if self.color_var and self.color_var.is_discrete:
colors = self.color_var.colors
- color_col = self.data[mask].get_column_view(self.color_var)[0]
+ color_col = self.data[mask].get_column(self.color_var)
color_labels = self.color_var.values
self.graph.set_data(self.data[mask], self.feature,
diff --git a/orangecontrib/explain/widgets/tests/test_owice.py b/orangecontrib/explain/widgets/tests/test_owice.py
index 5100bb5..c1538f6 100644
--- a/orangecontrib/explain/widgets/tests/test_owice.py
+++ b/orangecontrib/explain/widgets/tests/test_owice.py
@@ -1,12 +1,13 @@
# pylint: disable=missing-docstring
import unittest
-from unittest.mock import Mock
+from unittest.mock import Mock, patch
from AnyQt.QtCore import Qt, QPointF
from Orange.classification import RandomForestLearner, CalibratedLearner, \
ThresholdLearner, SimpleRandomForestLearner as SimpleRandomForestClassifier
from Orange.data import Table
+from Orange.data.table import DomainTransformationError
from Orange.regression import RandomForestRegressionLearner, \
SimpleRandomForestLearner
from Orange.tests.test_classification import all_learners as all_cls_learners
@@ -39,15 +40,19 @@ def test_input_cls(self):
self.send_signal(self.widget.Inputs.model, self.rf_reg)
self.wait_until_finished()
- self.assertTrue(self.widget.Error.unknown_err.is_shown())
+ # no error since no attributes in view and those no future is selected
+ self.assertFalse(self.widget.Error.unknown_err.is_shown())
self.send_signal(self.widget.Inputs.model, None)
self.assertFalse(self.widget.Error.unknown_err.is_shown())
- self.send_signal(self.widget.Inputs.data, self.iris)
- self.send_signal(self.widget.Inputs.model, self.rf_cls)
- self.wait_until_finished()
- self.assertTrue(self.widget.Error.domain_transform_err.is_shown())
+ with patch(
+ "orangecontrib.explain.widgets.owice.individual_condition_expectation",
+ side_effect=DomainTransformationError
+ ):
+ self.send_signal(self.widget.Inputs.model, self.rf_cls)
+ self.wait_until_finished()
+ self.assertTrue(self.widget.Error.domain_transform_err.is_shown())
def test_output(self):
self.send_signal(self.widget.Inputs.data, self.heart)
From 4f6e91eee382842cb8dd38159a491f58a955b753 Mon Sep 17 00:00:00 2001
From: PrimozGodec
Date: Wed, 26 Jul 2023 12:33:26 +0200
Subject: [PATCH 5/5] Update oldest orange-widget-base for ListViewFilter
---
setup.py | 6 +++---
tox.ini | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/setup.py b/setup.py
index 020240b..558d64d 100644
--- a/setup.py
+++ b/setup.py
@@ -40,9 +40,9 @@
INSTALL_REQUIRES = [
"AnyQt",
"numpy",
- "Orange3 >= 3.33.0",
- "orange-widget-base",
- "orange-canvas-core",
+ "Orange3 >=3.34.0",
+ "orange-canvas-core >=0.1.28",
+ "orange-widget-base >=4.19.0",
"pyqtgraph",
"scipy",
"shap >=0.42.1",
diff --git a/tox.ini b/tox.ini
index 343efee..d7e474d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -23,9 +23,9 @@ deps =
{env:WEBENGINE_PYPI_NAME:PyQtWebEngine}=={env:WEBENGINE_PYPI_VERSION:5.15.*}
xgboost
oldest: scikit-learn==1.0.1
- oldest: orange3==3.33.0
- oldest: orange-canvas-core==0.1.27
- oldest: orange-widget-base==4.18.0
+ oldest: orange3==3.34.0
+ oldest: orange-canvas-core==0.1.28
+ oldest: orange-widget-base==4.19.0
latest: https://github.com/biolab/orange3/archive/refs/heads/master.zip#egg=orange3
latest: https://github.com/biolab/orange-canvas-core/archive/refs/heads/master.zip#egg=orange-canvas-core
latest: https://github.com/biolab/orange-widget-base/archive/refs/heads/master.zip#egg=orange-widget-base