def test_regression(self): table = Table("housing")[::10] freeviz = FreeViz() freeviz(table) freeviz = FreeViz(p=2) freeviz(table)
def test_prepare_freeviz_data(self): table = Table("iris") FreeViz.prepare_freeviz_data(table) table.X = table.X * np.nan self.assertEqual(FreeViz.prepare_freeviz_data(table), (None, None, None)) table.X = None FreeViz.prepare_freeviz_data(table)
def test_weights(self): table = Table("iris") weights = np.random.rand(150, 1).flatten() freeviz = FreeViz(weights=weights, p=3, scale=False, center=False) freeviz(table) scale = np.array([0.5, 0.4, 0.6, 0.8]) freeviz = FreeViz(scale=scale, center=[0.2, 0.6, 0.4, 0.2]) freeviz(table)
def setUp(self): anchors = FreeViz.init_radial(len(self.data.domain.attributes)) self.projector = projector = FreeViz(scale=False, center=False, initial=anchors, maxiter=10) self.projector.domain = self.data.domain self.projector.components_ = anchors.T self.projection = FreeVizModel(projector, projector.domain, 2) self.projection.pre_domain = self.data.domain
def init_projection(self): anchors = FreeViz.init_radial(len(self.effective_variables)) \ if self.initialization == InitType.Circular \ else FreeViz.init_random(len(self.effective_variables), 2) self.projector = FreeViz(scale=False, center=False, initial=anchors, maxiter=10) data = self.projector.preprocess(self.effective_data) self.projector.domain = data.domain self.projector.components_ = anchors.T self.projection = FreeVizModel(self.projector, self.projector.domain, 2) self.projection.pre_domain = data.domain self.projection.name = self.projector.name
def test_raising_errors(self): table = Table("iris") freeviz = FreeViz(initial=(2, 4)) self.assertRaises(ValueError, freeviz, table) scale = np.array([0.5, 0.4, 0.6]) freeviz = FreeViz(scale=scale) self.assertRaises(ValueError, freeviz, table) freeviz = FreeViz(center=[0.6, 0.4, 0.2]) self.assertRaises(ValueError, freeviz, table) weights = np.random.rand(100, 1).flatten() freeviz = FreeViz(weights=weights) self.assertRaises(ValueError, freeviz, table)
def test_transform_changed_domain(self): """ 1. Open data, apply some preprocessor, splits the data into two parts, use FreeViz on the first part, and then transform the second part. 2. Open data, split into two parts, apply the same preprocessor and FreeViz only on the first part, and then transform the second part. The transformed second part in (1) and (2) has to be the same. """ data = Table("titanic")[::10] normalize = Continuize() freeviz = FreeViz(maxiter=40) # normalize all ndata = normalize(data) model = freeviz(ndata[:100]) result_1 = model(ndata[100:]) # normalize only the "training" part ndata = normalize(data[:100]) model = freeviz(ndata) result_2 = model(data[100:]) np.testing.assert_almost_equal(result_1.X, result_2.X)
def test_basic(self): table = self.iris.copy() table[3, 3] = np.nan freeviz = FreeViz() model = freeviz(table) proj = model(table) self.assertEqual(len(proj), len(table)) self.assertTrue(np.isnan(proj.X).any()) np.testing.assert_array_equal(proj[:100], model(table[:100]))
class OWFreeViz(OWAnchorProjectionWidget, ConcurrentWidgetMixin): MAX_INSTANCES = 10000 name = "FreeViz" description = "Displays FreeViz projection" icon = "icons/Freeviz.svg" priority = 240 keywords = ["viz"] settings_version = 3 initialization = settings.Setting(InitType.Circular) GRAPH_CLASS = OWFreeVizGraph graph = settings.SettingProvider(OWFreeVizGraph) class Error(OWAnchorProjectionWidget.Error): no_class_var = widget.Msg("Data must have a target variable.") multiple_class_vars = widget.Msg( "Data must have a single target variable.") not_enough_class_vars = widget.Msg( "Target variable must have at least two unique values.") features_exceeds_instances = widget.Msg( "Number of features exceeds the number of instances.") too_many_data_instances = widget.Msg("Data is too large.") constant_data = widget.Msg("All data columns are constant.") not_enough_features = widget.Msg("At least two features are required.") class Warning(OWAnchorProjectionWidget.Warning): removed_features = widget.Msg("Categorical features with more than" " two values are not shown.") def __init__(self): OWAnchorProjectionWidget.__init__(self) ConcurrentWidgetMixin.__init__(self) def _add_controls(self): self.__add_controls_start_box() super()._add_controls() self.gui.add_control(self._effects_box, gui.hSlider, "Hide radius:", master=self.graph, value="hide_radius", minValue=0, maxValue=100, step=10, createLabel=False, callback=self.__radius_slider_changed) def __add_controls_start_box(self): box = gui.vBox(self.controlArea, box="Optimize", spacing=0) gui.comboBox(box, self, "initialization", label="Initialization:", items=InitType.items(), orientation=Qt.Horizontal, labelWidth=90, callback=self.__init_combo_changed) self.run_button = gui.button(box, self, "Start", self._toggle_run) @property def effective_variables(self): return [ a for a in self.data.domain.attributes if a.is_continuous or a.is_discrete and len(a.values) == 2 ] def __radius_slider_changed(self): self.graph.update_radius() def __init_combo_changed(self): self.Error.proj_error.clear() self.init_projection() self.setup_plot() self.commit.deferred() if self.task is not None: self._run() def _toggle_run(self): if self.task is not None: self.cancel() self.graph.set_sample_size(None) self.run_button.setText("Resume") self.commit.deferred() else: self._run() def _run(self): if self.data is None: return self.graph.set_sample_size(self.SAMPLE_SIZE) self.run_button.setText("Stop") self.start(run_freeviz, self.effective_data, self.projector) # ConcurrentWidgetMixin def on_partial_result(self, result: Result): assert isinstance(result.projector, FreeViz) assert isinstance(result.projection, FreeVizModel) self.projector = result.projector self.projection = result.projection self.graph.update_coordinates() self.graph.update_density() def on_done(self, result: Result): assert isinstance(result.projector, FreeViz) assert isinstance(result.projection, FreeVizModel) self.projector = result.projector self.projection = result.projection self.graph.set_sample_size(None) self.run_button.setText("Start") self.commit.deferred() def on_exception(self, ex: Exception): self.Error.proj_error(ex) self.graph.set_sample_size(None) self.run_button.setText("Start") # OWAnchorProjectionWidget def set_data(self, data): super().set_data(data) self.graph.set_sample_size(None) if self._invalidated: self.init_projection() def init_projection(self): if self.data is None: return anchors = FreeViz.init_radial(len(self.effective_variables)) \ if self.initialization == InitType.Circular \ else FreeViz.init_random(len(self.effective_variables), 2) self.projector = FreeViz(scale=False, center=False, initial=anchors, maxiter=10) data = self.projector.preprocess(self.effective_data) self.projector.domain = data.domain self.projector.components_ = anchors.T self.projection = FreeVizModel(self.projector, self.projector.domain, 2) self.projection.pre_domain = data.domain self.projection.name = self.projector.name def check_data(self): def error(err): err() self.data = None super().check_data() if self.data is not None: class_vars, domain = self.data.domain.class_vars, self.data.domain if not class_vars: error(self.Error.no_class_var) elif len(class_vars) > 1: error(self.Error.multiple_class_vars) elif class_vars[0].is_discrete and len(np.unique(self.data.Y)) < 2: error(self.Error.not_enough_class_vars) elif len(self.data.domain.attributes) < 2: error(self.Error.not_enough_features) elif len(self.data.domain.attributes) > self.data.X.shape[0]: error(self.Error.features_exceeds_instances) elif not np.sum(np.std(self.data.X, axis=0)): error(self.Error.constant_data) elif np.sum(np.all(np.isfinite(self.data.X), axis=1)) > self.MAX_INSTANCES: error(self.Error.too_many_data_instances) else: if len(self.effective_variables) < len(domain.attributes): self.Warning.removed_features() def enable_controls(self): super().enable_controls() self.run_button.setEnabled(self.data is not None) self.run_button.setText("Start") def get_coordinates_data(self): embedding = self.get_embedding() if embedding is None: return None, None valid_emb = embedding[self.valid_data] return valid_emb.T / (np.max(np.linalg.norm(valid_emb, axis=1)) or 1) def _manual_move(self, anchor_idx, x, y): self.projector.initial[anchor_idx] = [x, y] super()._manual_move(anchor_idx, x, y) def clear(self): super().clear() self.cancel() def onDeleteWidget(self): self.shutdown() super().onDeleteWidget() @classmethod def migrate_settings(cls, _settings, version): if version < 3: if "radius" in _settings: _settings["graph"]["hide_radius"] = _settings["radius"] @classmethod def migrate_context(cls, context, version): if version < 3: values = context.values values["attr_color"] = values["graph"]["attr_color"] values["attr_size"] = values["graph"]["attr_size"] values["attr_shape"] = values["graph"]["attr_shape"] values["attr_label"] = values["graph"]["attr_label"]
class OWFreeViz(OWAnchorProjectionWidget): MAX_ITERATIONS = 1000 MAX_INSTANCES = 10000 name = "FreeViz" description = "Displays FreeViz projection" icon = "icons/Freeviz.svg" priority = 240 keywords = ["viz"] settings_version = 3 initialization = settings.Setting(InitType.Circular) GRAPH_CLASS = OWFreeVizGraph graph = settings.SettingProvider(OWFreeVizGraph) class Error(OWAnchorProjectionWidget.Error): no_class_var = widget.Msg("Data has no target variable") not_enough_class_vars = widget.Msg( "Target variable is not at least binary") features_exceeds_instances = widget.Msg( "Number of features exceeds the number of instances.") too_many_data_instances = widget.Msg("Data is too large.") constant_data = widget.Msg("All data columns are constant.") not_enough_features = widget.Msg("At least two features are required") class Warning(OWAnchorProjectionWidget.Warning): removed_features = widget.Msg("Categorical features with more than" " two values are not shown.") def __init__(self): super().__init__() self._loop = AsyncUpdateLoop(parent=self) self._loop.yielded.connect(self.__set_projection) self._loop.finished.connect(self.__freeviz_finished) self._loop.raised.connect(self.__on_error) def _add_controls(self): self.__add_controls_start_box() super()._add_controls() self.graph.gui.add_control(self._effects_box, gui.hSlider, "Hide radius:", master=self.graph, value="hide_radius", minValue=0, maxValue=100, step=10, createLabel=False, callback=self.__radius_slider_changed) def __add_controls_start_box(self): box = gui.vBox(self.controlArea, box=True) gui.comboBox(box, self, "initialization", label="Initialization:", items=InitType.items(), orientation=Qt.Horizontal, labelWidth=90, callback=self.__init_combo_changed) self.btn_start = gui.button(box, self, "Optimize", self.__toggle_start, enabled=False) @property def effective_variables(self): return [ a for a in self.data.domain.attributes if a.is_continuous or a.is_discrete and len(a.values) == 2 ] def __radius_slider_changed(self): self.graph.update_radius() def __toggle_start(self): if self._loop.isRunning(): self._loop.cancel() self.btn_start.setText("Optimize") self.progressBarFinished(processEvents=False) else: self._start() def __init_combo_changed(self): if self.data is None: return running = self._loop.isRunning() if running: self._loop.cancel() self.init_projection() self.graph.update_coordinates() self.commit() if running: self._start() def _start(self): def update_freeviz(anchors): while True: self.projection = self.projector(self.effective_data) _anchors = self.projector.components_.T self.projector.initial = _anchors yield _anchors if np.allclose(anchors, _anchors, rtol=1e-5, atol=1e-4): return anchors = _anchors self.graph.set_sample_size(self.SAMPLE_SIZE) self._loop.setCoroutine(update_freeviz(self.projector.components_.T)) self.btn_start.setText("Stop") self.progressBarInit() self.setBlocking(True) self.setStatusMessage("Optimizing") def __set_projection(self, _): # Set/update the projection matrix and coordinate embeddings self.progressBarAdvance(100. / self.MAX_ITERATIONS) self.graph.update_coordinates() def __freeviz_finished(self): self.graph.set_sample_size(None) self.btn_start.setText("Optimize") self.setStatusMessage("") self.setBlocking(False) self.progressBarFinished() self.commit() def __on_error(self, err): sys.excepthook(type(err), err, getattr(err, "__traceback__")) def check_data(self): def error(err): err() self.data = None super().check_data() if self.data is not None: class_var, domain = self.data.domain.class_var, self.data.domain if class_var is None: error(self.Error.no_class_var) elif class_var.is_discrete and len(np.unique(self.data.Y)) < 2: error(self.Error.not_enough_class_vars) elif len(self.data.domain.attributes) < 2: error(self.Error.not_enough_features) elif len(self.data.domain.attributes) > self.data.X.shape[0]: error(self.Error.features_exceeds_instances) elif not np.sum(np.std(self.data.X, axis=0)): error(self.Error.constant_data) elif np.sum(self.valid_data) > self.MAX_INSTANCES: error(self.Error.too_many_data_instances) else: if len(self.effective_variables) < len(domain.attributes): self.Warning.removed_features() self.btn_start.setEnabled(self.data is not None) def set_data(self, data): super().set_data(data) if self.data is not None: self.init_projection() def init_projection(self): anchors = FreeViz.init_radial(len(self.effective_variables)) \ if self.initialization == InitType.Circular \ else FreeViz.init_random(len(self.effective_variables), 2) self.projector = FreeViz(scale=False, center=False, initial=anchors, maxiter=10) data = self.projector.preprocess(self.effective_data) self.projector.domain = data.domain self.projector.components_ = anchors.T self.projection = FreeVizModel(self.projector, self.projector.domain) self.projection.pre_domain = data.domain self.projection.name = self.projector.name def get_coordinates_data(self): embedding = self.get_embedding() if embedding is None: return None, None valid_emb = embedding[self.valid_data] return valid_emb.T / (np.max(np.linalg.norm(valid_emb, axis=1)) or 1) def _manual_move(self, anchor_idx, x, y): self.projector.initial[anchor_idx] = [x, y] super()._manual_move(anchor_idx, x, y) def clear(self): super().clear() self._loop.cancel() @classmethod def migrate_settings(cls, _settings, version): if version < 3: if "radius" in _settings: _settings["graph"]["hide_radius"] = _settings["radius"] @classmethod def migrate_context(cls, context, version): if version < 3: values = context.values values["attr_color"] = values["graph"]["attr_color"] values["attr_size"] = values["graph"]["attr_size"] values["attr_shape"] = values["graph"]["attr_shape"] values["attr_label"] = values["graph"]["attr_label"]
def test_initial(self): FreeViz.init_radial(1) FreeViz.init_radial(2) FreeViz.init_radial(3) FreeViz.init_random(2, 4, 5)
def test_basic(self): table = Table("iris") table[3, 3] = np.nan freeviz = FreeViz() model = freeviz(table) model(table)
class OWFreeViz(OWAnchorProjectionWidget): MAX_ITERATIONS = 1000 MAX_INSTANCES = 10000 name = "FreeViz" description = "Displays FreeViz projection" icon = "icons/Freeviz.svg" priority = 240 keywords = ["viz"] settings_version = 3 initialization = settings.Setting(InitType.Circular) GRAPH_CLASS = OWFreeVizGraph graph = settings.SettingProvider(OWFreeVizGraph) class Error(OWAnchorProjectionWidget.Error): no_class_var = widget.Msg("Data has no target variable") not_enough_class_vars = widget.Msg( "Target variable is not at least binary") features_exceeds_instances = widget.Msg( "Number of features exceeds the number of instances.") too_many_data_instances = widget.Msg("Data is too large.") constant_data = widget.Msg("All data columns are constant.") not_enough_features = widget.Msg("At least two features are required") class Warning(OWAnchorProjectionWidget.Warning): removed_features = widget.Msg("Categorical features with more than" " two values are not shown.") def __init__(self): super().__init__() self._loop = AsyncUpdateLoop(parent=self) self._loop.yielded.connect(self.__set_projection) self._loop.finished.connect(self.__freeviz_finished) self._loop.raised.connect(self.__on_error) def _add_controls(self): self.__add_controls_start_box() super()._add_controls() self.gui.add_control( self._effects_box, gui.hSlider, "Hide radius:", master=self.graph, value="hide_radius", minValue=0, maxValue=100, step=10, createLabel=False, callback=self.__radius_slider_changed ) def __add_controls_start_box(self): box = gui.vBox(self.controlArea, box=True) gui.comboBox( box, self, "initialization", label="Initialization:", items=InitType.items(), orientation=Qt.Horizontal, labelWidth=90, callback=self.__init_combo_changed) self.btn_start = gui.button( box, self, "Optimize", self.__toggle_start, enabled=False) @property def effective_variables(self): return [a for a in self.data.domain.attributes if a.is_continuous or a.is_discrete and len(a.values) == 2] def __radius_slider_changed(self): self.graph.update_radius() def __toggle_start(self): if self._loop.isRunning(): self._loop.cancel() self.btn_start.setText("Optimize") self.progressBarFinished(processEvents=False) else: self._start() def __init_combo_changed(self): if self.data is None: return running = self._loop.isRunning() if running: self._loop.cancel() self.init_projection() self.graph.update_coordinates() self.commit() if running: self._start() def _start(self): def update_freeviz(anchors): while True: self.projection = self.projector(self.effective_data) _anchors = self.projector.components_.T self.projector.initial = _anchors yield _anchors if np.allclose(anchors, _anchors, rtol=1e-5, atol=1e-4): return anchors = _anchors self.graph.set_sample_size(self.SAMPLE_SIZE) self._loop.setCoroutine(update_freeviz(self.projector.components_.T)) self.btn_start.setText("Stop") self.progressBarInit() self.setBlocking(True) self.setStatusMessage("Optimizing") def __set_projection(self, _): # Set/update the projection matrix and coordinate embeddings self.progressBarAdvance(100. / self.MAX_ITERATIONS) self.graph.update_coordinates() def __freeviz_finished(self): self.graph.set_sample_size(None) self.btn_start.setText("Optimize") self.setStatusMessage("") self.setBlocking(False) self.progressBarFinished() self.commit() def __on_error(self, err): sys.excepthook(type(err), err, getattr(err, "__traceback__")) def check_data(self): def error(err): err() self.data = None super().check_data() if self.data is not None: class_var, domain = self.data.domain.class_var, self.data.domain if class_var is None: error(self.Error.no_class_var) elif class_var.is_discrete and len(np.unique(self.data.Y)) < 2: error(self.Error.not_enough_class_vars) elif len(self.data.domain.attributes) < 2: error(self.Error.not_enough_features) elif len(self.data.domain.attributes) > self.data.X.shape[0]: error(self.Error.features_exceeds_instances) elif not np.sum(np.std(self.data.X, axis=0)): error(self.Error.constant_data) elif np.sum(self.valid_data) > self.MAX_INSTANCES: error(self.Error.too_many_data_instances) else: if len(self.effective_variables) < len(domain.attributes): self.Warning.removed_features() self.btn_start.setEnabled(self.data is not None) def set_data(self, data): super().set_data(data) if self.data is not None: self.init_projection() def init_projection(self): anchors = FreeViz.init_radial(len(self.effective_variables)) \ if self.initialization == InitType.Circular \ else FreeViz.init_random(len(self.effective_variables), 2) self.projector = FreeViz(scale=False, center=False, initial=anchors, maxiter=10) data = self.projector.preprocess(self.effective_data) self.projector.domain = data.domain self.projector.components_ = anchors.T self.projection = FreeVizModel(self.projector, self.projector.domain, 2) self.projection.pre_domain = data.domain self.projection.name = self.projector.name def get_coordinates_data(self): embedding = self.get_embedding() if embedding is None: return None, None valid_emb = embedding[self.valid_data] return valid_emb.T / (np.max(np.linalg.norm(valid_emb, axis=1)) or 1) def _manual_move(self, anchor_idx, x, y): self.projector.initial[anchor_idx] = [x, y] super()._manual_move(anchor_idx, x, y) def clear(self): super().clear() self._loop.cancel() @classmethod def migrate_settings(cls, _settings, version): if version < 3: if "radius" in _settings: _settings["graph"]["hide_radius"] = _settings["radius"] @classmethod def migrate_context(cls, context, version): if version < 3: values = context.values values["attr_color"] = values["graph"]["attr_color"] values["attr_size"] = values["graph"]["attr_size"] values["attr_shape"] = values["graph"]["attr_shape"] values["attr_label"] = values["graph"]["attr_label"]
class OWFreeViz(OWAnchorProjectionWidget, ConcurrentWidgetMixin): MAX_INSTANCES = 10000 name = "FreeViz" description = "Displays FreeViz projection" icon = "icons/Freeviz.svg" priority = 240 keywords = ["viz"] settings_version = 3 initialization = settings.Setting(InitType.Circular) GRAPH_CLASS = OWFreeVizGraph graph = settings.SettingProvider(OWFreeVizGraph) left_side_scrolling = True class Error(OWAnchorProjectionWidget.Error): no_class_var = widget.Msg("Data has no target variable") not_enough_class_vars = widget.Msg( "Target variable is not at least binary") features_exceeds_instances = widget.Msg( "Number of features exceeds the number of instances.") too_many_data_instances = widget.Msg("Data is too large.") constant_data = widget.Msg("All data columns are constant.") not_enough_features = widget.Msg("At least two features are required") class Warning(OWAnchorProjectionWidget.Warning): removed_features = widget.Msg("Categorical features with more than" " two values are not shown.") def __init__(self): OWAnchorProjectionWidget.__init__(self) ConcurrentWidgetMixin.__init__(self) def _add_controls(self): self.__add_controls_start_box() super()._add_controls() self.gui.add_control( self._effects_box, gui.hSlider, "Hide radius:", master=self.graph, value="hide_radius", minValue=0, maxValue=100, step=10, createLabel=False, callback=self.__radius_slider_changed ) def __add_controls_start_box(self): box = gui.vBox(self.controlArea, box=True) gui.comboBox( box, self, "initialization", label="Initialization:", items=InitType.items(), orientation=Qt.Horizontal, labelWidth=90, callback=self.__init_combo_changed) self.run_button = gui.button(box, self, "Start", self._toggle_run) @property def effective_variables(self): return [a for a in self.data.domain.attributes if a.is_continuous or a.is_discrete and len(a.values) == 2] def __radius_slider_changed(self): self.graph.update_radius() def __init_combo_changed(self): self.Error.proj_error.clear() self.init_projection() self.setup_plot() self.commit() if self.task is not None: self._run() def _toggle_run(self): if self.task is not None: self.cancel() self.graph.set_sample_size(None) self.run_button.setText("Resume") self.commit() else: self._run() def _run(self): if self.data is None: return self.graph.set_sample_size(self.SAMPLE_SIZE) self.run_button.setText("Stop") self.start(run_freeviz, self.effective_data, self.projector) # ConcurrentWidgetMixin def on_partial_result(self, result: Result): assert isinstance(result.projector, FreeViz) assert isinstance(result.projection, FreeVizModel) self.projector = result.projector self.projection = result.projection self.graph.update_coordinates() self.graph.update_density() def on_done(self, result: Result): assert isinstance(result.projector, FreeViz) assert isinstance(result.projection, FreeVizModel) self.projector = result.projector self.projection = result.projection self.graph.set_sample_size(None) self.run_button.setText("Start") self.commit() def on_exception(self, ex: Exception): self.Error.proj_error(ex) self.graph.set_sample_size(None) self.run_button.setText("Start") # OWAnchorProjectionWidget def set_data(self, data): super().set_data(data) if self._invalidated: self.init_projection() def init_projection(self): if self.data is None: return anchors = FreeViz.init_radial(len(self.effective_variables)) \ if self.initialization == InitType.Circular \ else FreeViz.init_random(len(self.effective_variables), 2) self.projector = FreeViz(scale=False, center=False, initial=anchors, maxiter=10) data = self.projector.preprocess(self.effective_data) self.projector.domain = data.domain self.projector.components_ = anchors.T self.projection = FreeVizModel(self.projector, self.projector.domain, 2) self.projection.pre_domain = data.domain self.projection.name = self.projector.name def check_data(self): def error(err): err() self.data = None super().check_data() if self.data is not None: class_var, domain = self.data.domain.class_var, self.data.domain if class_var is None: error(self.Error.no_class_var) elif class_var.is_discrete and len(np.unique(self.data.Y)) < 2: error(self.Error.not_enough_class_vars) elif len(self.data.domain.attributes) < 2: error(self.Error.not_enough_features) elif len(self.data.domain.attributes) > self.data.X.shape[0]: error(self.Error.features_exceeds_instances) elif not np.sum(np.std(self.data.X, axis=0)): error(self.Error.constant_data) elif np.sum(np.all(np.isfinite(self.data.X), axis=1)) > self.MAX_INSTANCES: error(self.Error.too_many_data_instances) else: if len(self.effective_variables) < len(domain.attributes): self.Warning.removed_features() def enable_controls(self): super().enable_controls() self.run_button.setEnabled(self.data is not None) self.run_button.setText("Start") def get_coordinates_data(self): embedding = self.get_embedding() if embedding is None: return None, None valid_emb = embedding[self.valid_data] return valid_emb.T / (np.max(np.linalg.norm(valid_emb, axis=1)) or 1) def _manual_move(self, anchor_idx, x, y): self.projector.initial[anchor_idx] = [x, y] super()._manual_move(anchor_idx, x, y) def clear(self): super().clear() self.cancel() def onDeleteWidget(self): self.shutdown() super().onDeleteWidget() @classmethod def migrate_settings(cls, _settings, version): if version < 3: if "radius" in _settings: _settings["graph"]["hide_radius"] = _settings["radius"] @classmethod def migrate_context(cls, context, version): if version < 3: values = context.values values["attr_color"] = values["graph"]["attr_color"] values["attr_size"] = values["graph"]["attr_size"] values["attr_shape"] = values["graph"]["attr_shape"] values["attr_label"] = values["graph"]["attr_label"]