From b45a4f59c65f26f627914cfdb4853d8c335f597d Mon Sep 17 00:00:00 2001 From: Jernej Urankar Date: Fri, 21 Jul 2017 15:19:21 +0200 Subject: [PATCH 1/6] Radviz: icon copied from Orange 2 --- Orange/widgets/visualize/icons/Radviz.svg | 37 +++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Orange/widgets/visualize/icons/Radviz.svg diff --git a/Orange/widgets/visualize/icons/Radviz.svg b/Orange/widgets/visualize/icons/Radviz.svg new file mode 100644 index 00000000000..031e83a52e5 --- /dev/null +++ b/Orange/widgets/visualize/icons/Radviz.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From ed38467a2070eeb1fb2e46e87e5b334480430aae Mon Sep 17 00:00:00 2001 From: Jernej Urankar Date: Thu, 3 Aug 2017 10:21:52 +0200 Subject: [PATCH 2/6] Radviz: Script --- Orange/projection/__init__.py | 1 + Orange/projection/radviz.py | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 Orange/projection/radviz.py diff --git a/Orange/projection/__init__.py b/Orange/projection/__init__.py index 5f5921bd320..dd577130b90 100644 --- a/Orange/projection/__init__.py +++ b/Orange/projection/__init__.py @@ -3,3 +3,4 @@ from .cur import * from .manifold import * from .freeviz import * +from .radviz import radviz diff --git a/Orange/projection/radviz.py b/Orange/projection/radviz.py new file mode 100644 index 00000000000..efd026ac278 --- /dev/null +++ b/Orange/projection/radviz.py @@ -0,0 +1,45 @@ +import numpy as np + +from Orange.data import Domain + + +def radviz(data, attrs, points=None): + x = data.transform(domain=Domain(attrs)).X + mask = ~np.isnan(x).any(axis=1) + x = x[mask] + + n = len(x) + if not n: + return None, None, mask + x = normalize(x) + + r_x = np.zeros(n) + r_y = np.zeros(n) + + m = x.shape[1] + if points is not None: + s = points[:, :2] + else: + s = np.array([(np.cos(t), np.sin(t)) + for t in [2.0 * np.pi * (i / float(m)) + for i in range(m)]]) + for i in range(n): + row = x[i] + row_ = np.repeat(np.expand_dims(row, axis=1), 2, axis=1) + with np.errstate(divide='ignore', invalid='ignore'): + a = (s * row_).sum(axis=0) + b = row.sum() + y = np.divide(a, b, out=np.zeros_like(a), where=b != 0) + r_x[i] = y[0] + r_y[i] = y[1] + + return np.stack((r_x, r_y), axis=1), np.column_stack((s, attrs)), mask + + +def normalize(x): + """ + MinMax normalization to fit a matrix in the space [0,1] by column. + """ + a = x.min(axis=0) + b = x.max(axis=0) + return (x - a[np.newaxis, :]) / ((b - a)[np.newaxis, :]) From 56e098d1cc16ec828f190d3a64e00f12525daa0a Mon Sep 17 00:00:00 2001 From: Jernej Urankar Date: Thu, 3 Aug 2017 10:21:52 +0200 Subject: [PATCH 3/6] [ENH] Radviz: new widget add circle and points around add circle points labels fix Inputs/Outputs data validation aspect ratio = 1 (circle, not ellipse) commit selection and selection groups hide axis fix divide max attrs, displayed box height use old point on the circle move points on a circle fix commit icon added do not show main axis when there is no data script fix filter on mouse hover larger circle point labels fix view box clear fix --- Orange/widgets/visualize/owradviz.py | 949 +++++++++++++++++++++++++++ 1 file changed, 949 insertions(+) create mode 100644 Orange/widgets/visualize/owradviz.py diff --git a/Orange/widgets/visualize/owradviz.py b/Orange/widgets/visualize/owradviz.py new file mode 100644 index 00000000000..534c352a350 --- /dev/null +++ b/Orange/widgets/visualize/owradviz.py @@ -0,0 +1,949 @@ +from itertools import islice, permutations, chain +from math import factorial +from types import SimpleNamespace as namespace +from xml.sax.saxutils import escape +import warnings + +import numpy as np +from scipy.spatial import distance + +from AnyQt.QtGui import QStandardItem, QColor, QFontMetrics, QCursor +from AnyQt.QtCore import Qt, QEvent, QSize, QRectF, QPoint +from AnyQt.QtCore import pyqtSignal as Signal +from AnyQt.QtWidgets import qApp, QSizePolicy, QApplication, QToolTip, QGraphicsSceneMouseEvent + +import pyqtgraph as pg +from pyqtgraph.graphicsItems.ScatterPlotItem import ScatterPlotItem + +from sklearn.model_selection import cross_val_score +from sklearn.neighbors import KNeighborsClassifier + +from Orange.data import Table, Domain, ContinuousVariable, StringVariable +from Orange.data.sql.table import SqlTable +from Orange.preprocess.score import ReliefF +from Orange.projection import radviz +from Orange.widgets import widget, gui, settings +from Orange.widgets.gui import OWComponent +from Orange.widgets.settings import Setting +from Orange.widgets.utils.annotated_data import ( + create_annotated_table, ANNOTATED_DATA_SIGNAL_NAME, create_groups_table) +from Orange.widgets.utils.itemmodels import VariableListModel +from Orange.widgets.utils.plot import VariablesSelection +from Orange.widgets.visualize.utils import VizRankDialog +from Orange.widgets.visualize.owscatterplotgraph import OWScatterPlotGraph, InteractiveViewBox, \ + HelpEventDelegate +from Orange.widgets.visualize.utils.plotutils import TextItem +from Orange.widgets.widget import Input, Output +from Orange.canvas import report + + +class RadvizVizRank(VizRankDialog, OWComponent): + captionTitle = "Score Plots" + n_attrs = settings.Setting(6) + minK = 10 + + attrsSelected = Signal([]) + _AttrRole = next(gui.OrangeUserRole) + + percent_data_used = Setting(100) + + def __init__(self, master): + """Add the spin box for maximal number of attributes""" + VizRankDialog.__init__(self, master) + OWComponent.__init__(self, master) + + self.master = master + self.n_neighbors = 10 + max_n_attrs = len(master.model_selected) + len(master.model_other) - 1 + + box = gui.hBox(self) + self.n_attrs_spin = gui.spin( + box, self, "n_attrs", 4, max_n_attrs, label="Number of variables: ", + controlWidth=50, alignment=Qt.AlignRight, callback=self._n_attrs_changed) + gui.rubber(box) + self.last_run_n_attrs = None + self.attr_color = master.graph.attr_color + + self.attr_ordering = None + self.last_run_n_attrs = None + self.attr_color = master.graph.attr_color + self.data = None + self.valid_data = None + + def initialize(self): + super().initialize() + self.attr_color = self.master.graph.attr_color + + def _compute_attr_order(self): + """ + used by VizRank to evaluate attributes + """ + master = self.master + attrs = [v for v in chain(master.model_selected[:], master.model_other[:]) + if v is not self.attr_color] + data = self.master.data.transform(Domain(attributes=attrs, class_vars=self.attr_color)) + self.data = data + self.valid_data = np.hstack((~np.isnan(data.X), ~np.isnan(data.Y.reshape(len(data.Y), 1)))) + weights = ReliefF(n_iterations=100, k_nearest=self.minK)(data) + attrs = sorted(zip(weights, attrs), key=lambda x: (-x[0], x[1].name)) + self.attr_ordering = attr_ordering = [a for _, a in attrs] + return attr_ordering + + def _evaluate_projection(self, x, y): + """ + kNNEvaluate - evaluate class separation in the given projection using a k-NN method + Parameters + ---------- + x - variables to evaluate + y - class + + Returns + ------- + scores + """ + if self.percent_data_used != 100: + rand = np.random.choice(len(x), int(len(x) * self.percent_data_used / 100), + replace=False) + x = x[rand] + y = y[rand] + neigh = KNeighborsClassifier(n_neighbors=3) + assert ~(np.isnan(x).any(axis=None) | np.isnan(x).any(axis=None)) + neigh.fit(x, y) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=UserWarning) + scores = cross_val_score(neigh, x, y, cv=3) + return scores.mean() + + def _n_attrs_changed(self): + """ + Change the button label when the number of attributes changes. The method does not reset + anything so the user can still see the results until actually restarting the search. + """ + if self.n_attrs != self.last_run_n_attrs or self.saved_state is None: + self.button.setText("Start") + else: + self.button.setText("Continue") + self.button.setEnabled(self.check_preconditions()) + + def progressBarSet(self, value, processEvents=None): + self.setWindowTitle(self.captionTitle + " Evaluated {} permutations".format(value)) + if processEvents is not None and processEvents is not False: + qApp.processEvents(processEvents) + + def check_preconditions(self): + master = self.master + if not super().check_preconditions(): + return False + elif not master.btn_vizrank.isEnabled(): + return False + self.n_attrs_spin.setMaximum(20) # all primitive vars except color one + return True + + def on_selection_changed(self, selected, deselected): + attrs = selected.indexes()[0].data(self._AttrRole) + self.selectionChanged.emit([attrs]) + + def iterate_states(self, state): + if state is None: # on the first call, compute order + self.attrs = self._compute_attr_order() + state = list(range(self.n_attrs)) + else: + state = list(state) + + def combinations(n, s): + while True: + yield s + for up, _ in enumerate(s): + s[up] += 1 + if up + 1 == len(s) or s[up] < s[up + 1]: + break + s[up] = up + if s[-1] == n: + break + + for c in combinations(len(self.attrs), state): + for p in islice(permutations(c[1:]), factorial(len(c) - 1) // 2): + yield (c[0],) + p + + def compute_score(self, state): + attrs = [self.attrs[i] for i in state] + domain = Domain(attributes=attrs, class_vars=[self.attr_color]) + data = self.data.transform(domain) + radviz_xy, _, mask = radviz(data, attrs) + y = data.Y[mask] + return -self._evaluate_projection(radviz_xy, y) + + def bar_length(self, score): + return -score + + def row_for_state(self, score, state): + attrs = [self.attrs[s] for s in state] + item = QStandardItem("[{:0.6f}] ".format(-score) + ", ".join(a.name for a in attrs)) + item.setData(attrs, self._AttrRole) + return [item] + + def _update_progress(self): + self.progressBarSet(int(self.saved_progress)) + + def before_running(self): + """ + Disable the spin for number of attributes before running and + enable afterwards. Also, if the number of attributes is different than + in the last run, reset the saved state (if it was paused). + """ + if self.n_attrs != self.last_run_n_attrs: + self.saved_state = None + self.saved_progress = 0 + if self.saved_state is None: + self.scores = [] + self.rank_model.clear() + self.last_run_n_attrs = self.n_attrs + + +class RadvizInteractiveViewBox(InteractiveViewBox): + def __init__(self, graph, enable_menu=False): + self.mouse_state = 0 + self.point_i = None + self.cursor = QCursor() + super().__init__(graph, enable_menu) + + def _dragtip_pos(self): + return 10, 10 + + def mouseDragEvent(self, ev, axis=None): + master = self.graph.master + if master.data is None or master.graph.data is None: + super().mouseDragEvent(ev, axis) + return + + pos = self.childGroup.mapFromParent(ev.pos()) + points = master.plotdata.points + np_pos = np.array([[pos.x(), pos.y()]]) + distances = distance.cdist(np_pos, points[:, :2]) + is_near = np.min(distances) < 0.1 + + if ev.button() != Qt.LeftButton or (ev.start and not is_near): + self.mouse_state = 2 + if self.mouse_state == 2: + if ev.finish: + self.mouse_state = 0 + super().mouseDragEvent(ev, axis) + return + + ev.accept() + if ev.start: + self.cursor.setShape(Qt.ClosedHandCursor) + self.setCursor(self.cursor) + self.mouse_state = 1 + self.point_i = np.argmin(distances) + master.randomize_indices() + if self.mouse_state == 1: + if ev.finish: + self.cursor.setShape(Qt.ArrowCursor) + self.setCursor(self.cursor) + self.mouse_state = 0 + angle = np.arctan2(pos.y(), pos.x()) + QToolTip.showText( + QPoint(ev.screenPos().x(), ev.screenPos().y()), "{:.2f}".format(np.rad2deg(angle))) + points[self.point_i][0] = np.cos(angle) + points[self.point_i][1] = np.sin(angle) + if ev.finish: + master.setup_plot() + master.commit() + else: + master.manual_move() + self.graph.show_arc_arrow(pos.x(), pos.y()) + + +class EventDelegate(HelpEventDelegate): + def __init__(self, delegate, delegate2, parent=None): + self.delegate2 = delegate2 + super().__init__(delegate, parent=parent) + + def eventFilter(self, obj, ev): + if isinstance(ev, QGraphicsSceneMouseEvent): + self.delegate2(ev) + return super().eventFilter(obj, ev) + + + +SELECTION_WIDTH = 5 + +class OWRadvizGraph(OWScatterPlotGraph): + jitter_size = settings.Setting(0) + + def __init__(self, scatter_widget, parent=None, name="None", view_box=None): + super().__init__(scatter_widget, parent=parent, _=name, view_box=view_box) + self._tooltip_delegate = EventDelegate(self.help_event, self._show_arc) + self.plot_widget.scene().installEventFilter(self._tooltip_delegate) + self.scatterplot_points = ScatterPlotItem(x=[], y=[]) + + def hide_axes(self): + for axis in ["left", "bottom"]: + self.plot_widget.hideAxis(axis) + + def update_data(self, attr_x, attr_y, reset_view=True): + super().update_data(attr_x, attr_y, reset_view) + self.hide_axes() + if reset_view: + self.view_box.setRange(RANGE, padding=0.025) + self.view_box.setAspectLocked(True, 1) + + def show_arc_arrow(self, x=None, y=None, point_i=None): + def remove_arc_arrows(): + for arcarrow in self.master.plotdata.arcarrows: + self.plot_widget.removeItem(arcarrow) + self.master.plotdata.arcarrows = [] + def add_arc_arrows(x, y, col): + func = self.view_box.childGroup.mapToDevice + dx = (func(QPoint(1, 0)) - func(QPoint(-1, 0))).x() + dangle = 6000 / dx + arc = add_arc(np.arctan2(y, x), col, dangle) + for a in arc: + self.plot_widget.addItem(a) + self.master.plotdata.arcarrows += arc + + remove_arc_arrows() + if self.view_box.mouse_state == 0 and point_i is not None: + point = self.master.plotdata.points[point_i, :] + add_arc_arrows(point[0], point[1], 1) + if self.view_box.mouse_state == 1 and x is not None: + add_arc_arrows(x, y, 0) + + def _show_arc(self, ev): + if self.scatterplot_item is None: + return False + if self.view_box.mouse_state == 1: + return True + + for arcarrow in self.master.plotdata.arcarrows: + self.plot_widget.removeItem(arcarrow) + self.master.plotdata.arcarrows = [] + + pos = self.scatterplot_item.mapFromScene(ev.scenePos()) + x = pos.x() + y = pos.y() + points = self.master.plotdata.points + + np_pos = np.array([[x, y]]) + distances = distance.cdist(np_pos, points[:, :2])[0] + if len(distances) and np.min(distances) < 0.08: + self.view_box.cursor.setShape(Qt.OpenHandCursor) + self.view_box.setCursor(self.view_box.cursor) + self.show_arc_arrow(point_i=np.argmin(distances)) + else: + self.view_box.cursor.setShape(Qt.ArrowCursor) + self.view_box.setCursor(self.view_box.cursor) + return True + + def help_event(self, event): + if self.scatterplot_item is None: + return False + + act_pos = self.scatterplot_item.mapFromScene(event.scenePos()) + points = self.scatterplot_item.pointsAt(act_pos) + text = "" + vars = self.master.model_selected + if len(points): + for i, p in enumerate(points): + index = p.data() + text += "Attributes:\n" + text += "".join( + " {} = {}\n".format(attr.name, self.data[index][attr]) + for attr in vars) + if len(vars[:]) > 10: + text += " ... and {} others\n\n".format(len(vars[:]) - 12) + # class_var is always: + text += "Class:\n {} = {}\n".format(self.domain.class_var.name, + self.data[index][self.data.domain.class_var]) + if i < len(points) - 1: + text += '------------------\n' + text = ('{}'.format(escape(text))) + + QToolTip.showText(event.screenPos(), text, widget=self.plot_widget) + return True + return False + + +RANGE = QRectF(-1.2, -1.05, 2.4, 2.1) +MAX_ANCHORS = 16 +MAX_POINTS = 100 + +class OWRadviz(widget.OWWidget): + name = "Radviz" + description = "Radviz" + + icon = "icons/Radviz.svg" + priority = 240 + + class Inputs: + data = Input("Data", Table, default=True) + data_subset = Input("Data Subset", Table) + + class Outputs: + selected_data = Output("Selected Data", Table, default=True) + annotated_data = Output(ANNOTATED_DATA_SIGNAL_NAME, Table) + components = Output("Components", Table) + + settings_version = 1 + settingsHandler = settings.DomainContextHandler() + + variable_state = settings.ContextSetting({}) + + auto_commit = settings.Setting(True) + graph = settings.SettingProvider(OWRadvizGraph) + vizrank = settings.SettingProvider(RadvizVizRank) + + jitter_sizes = [0, 0.1, 0.5, 1.0, 2.0] + + ReplotRequest = QEvent.registerEventType() + + graph_name = "graph.plot_widget.plotItem" + + class Information(widget.OWWidget.Information): + sql_sampled_data = widget.Msg("Data has been sampled") + + class Warning(widget.OWWidget.Warning): + no_features = widget.Msg("At least 2 features has to be chosen") + + class Error(widget.OWWidget.Error): + sparse_data = widget.Msg("Sparse data is not supported") + no_features = widget.Msg("At least 3 numeric or categorical variables are required") + no_instances = widget.Msg("At least 2 data instances are required") + + def __init__(self): + super().__init__() + + self.data = None + self.subset_data = None + self._subset_mask = None + self._selection = None # np.array + self.__replot_requested = False + self._new_plotdata() + + self.variable_x = ContinuousVariable("radviz-x") + self.variable_y = ContinuousVariable("radviz-y") + + box = gui.vBox(self.mainArea, True, margin=0) + self.graph = OWRadvizGraph(self, box, "Plot", view_box=RadvizInteractiveViewBox) + self.graph.hide_axes() + + box.layout().addWidget(self.graph.plot_widget) + plot = self.graph.plot_widget + + SIZE_POLICY = (QSizePolicy.Minimum, QSizePolicy.Maximum) + + self.variables_selection = VariablesSelection() + self.model_selected = VariableListModel(enable_dnd=True) + self.model_other = VariableListModel(enable_dnd=True) + self.variables_selection(self, self.model_selected, self.model_other) + + self.vizrank, self.btn_vizrank = RadvizVizRank.add_vizrank( + self.controlArea, self, "Suggest features", self.vizrank_set_attrs) + self.btn_vizrank.setSizePolicy(*SIZE_POLICY) + self.variables_selection.add_remove.layout().addWidget(self.btn_vizrank) + + self.viewbox = plot.getViewBox() + self.replot = None + + g = self.graph.gui + pp_box = g.point_properties_box(self.controlArea) + pp_box.setSizePolicy(*SIZE_POLICY) + self.models = g.points_models + + box = gui.vBox(self.controlArea, "Plot Properties") + box.setSizePolicy(*SIZE_POLICY) + g.add_widget(g.JitterSizeSlider, box) + + g.add_widgets([g.ShowLegend, g.ClassDensity, g.LabelOnlySelected], box) + + zoom_select = self.graph.box_zoom_select(self.controlArea) + zoom_select.setSizePolicy(*SIZE_POLICY) + + self.icons = gui.attributeIconDict + + p = self.graph.plot_widget.palette() + self.graph.set_palette(p) + + gui.auto_commit(self.controlArea, self, "auto_commit", "Send Selection", + auto_label="Send Automatically") + + self.graph.zoom_actions(self) + + self._circle = pg.PlotCurveItem( + x=np.fromfunction(lambda i: np.cos(2. * np.pi * i / 120.), (121,), dtype=int), + y=np.fromfunction(lambda i: np.sin(2. * np.pi * i / 120.), (121,), dtype=int), + pen=pg.mkPen(QColor(0, 0, 0), width=2), + antialias=False + ) + + def resizeEvent(self, event): + self._update_points_labels() + + def keyPressEvent(self, event): + super().keyPressEvent(event) + self.graph.update_tooltip(event.modifiers()) + + def keyReleaseEvent(self, event): + super().keyReleaseEvent(event) + self.graph.update_tooltip(event.modifiers()) + + def vizrank_set_attrs(self, attrs): + if not attrs: + return + self.variables_selection.display_none() + self.model_selected[:] = attrs[:] + self.model_other[:] = [v for v in self.model_other if v not in attrs] + + def _new_plotdata(self): + self.plotdata = namespace( + valid_mask=None, + embedding_coords=None, + points=None, + circle=None, + arcarrows=[], + point_labels=[], + rand=None, + data=None, + ) + + def update_colors(self): + self._vizrank_color_change() + self.cb_class_density.setEnabled(self.graph.can_draw_density()) + + def sizeHint(self): + return QSize(800, 500) + + def clear(self): + """ + Clear/reset the widget state + """ + self.data = None + self.model_selected.clear() + self.model_other.clear() + self._clear_plot() + + def _clear_plot(self): + self._new_plotdata() + self.graph.plot_widget.clear() + + def invalidate_plot(self): + """ + Schedule a delayed replot. + """ + if not self.__replot_requested: + self.__replot_requested = True + QApplication.postEvent(self, QEvent(self.ReplotRequest), Qt.LowEventPriority - 10) + + def init_attr_values(self): + domain = self.data and len(self.data) and self.data.domain or None + for model in self.models: + model.set_domain(domain) + self.graph.attr_color = self.data.domain.class_var if domain else None + self.graph.attr_shape = None + self.graph.attr_size = None + self.graph.attr_label = None + + def _vizrank_color_change(self): + attr_color = self.graph.attr_color + is_enabled = self.data is not None and not self.data.is_sparse() and \ + (len(self.model_other) + len(self.model_selected)) > 3 and len(self.data) > 1 + self.btn_vizrank.setEnabled( + is_enabled and attr_color is not None and attr_color.is_discrete + and not np.isnan(self.data.get_column_view(attr_color)[0].astype(float)).all()) + if is_enabled and (attr_color is None or + (attr_color is not None and not attr_color.is_discrete)): + self.btn_vizrank.setToolTip("Discrete color variable has to be selected.") + else: + self.btn_vizrank.setToolTip("") + self.vizrank.initialize() + + @Inputs.data + def set_data(self, data): + """ + Set the input dataset and check if data is valid. + + Args: + data (Orange.data.table): data instances + """ + def sql(data): + self.Information.sql_sampled_data.clear() + if isinstance(data, SqlTable): + if data.approx_len() < 4000: + data = Table(data) + else: + self.Information.sql_sampled_data() + data_sample = data.sample_time(1, no_cache=True) + data_sample.download_data(2000, partial=True) + data = Table(data_sample) + return data + + def settings(data): + # get the default encoded state, replacing the position with Inf + state = VariablesSelection.encode_var_state( + [list(self.model_selected), list(self.model_other)] + ) + state = {key: (source_ind, np.inf) for key, (source_ind, _) in state.items()} + + self.openContext(data.domain) + selected_keys = [key + for key, (sind, _) in self.variable_state.items() + if sind == 0] + + if set(selected_keys).issubset(set(state.keys())): + pass + + # update the defaults state (the encoded state must contain + # all variables in the input domain) + state.update(self.variable_state) + # ... and restore it with saved positions taking precedence over + # the defaults + selected, other = VariablesSelection.decode_var_state( + state, [list(self.model_selected), list(self.model_other)]) + return selected, other + + def is_sparse(data): + if data.is_sparse(): + self.Error.sparse_data() + data = None + return data + + def are_features(data): + domain = data.domain + vars = [var for var in chain(domain.class_vars, domain.metas, domain.attributes) + if var.is_primitive()] + if len(vars) < 3: + self.Error.no_features() + data = None + return data + + def are_instances(data): + if len(data) < 2: + self.Error.no_instances() + data = None + return data + + self.clear_messages() + self.btn_vizrank.setEnabled(False) + self.closeContext() + self.clear() + self.information() + self.Error.clear() + for f in [sql, is_sparse, are_features, are_instances]: + if data is None: + break + data = f(data) + + if data is not None: + self.data = data + self.init_attr_values() + domain = data.domain + vars = [v for v in chain(domain.class_vars, domain.metas, domain.attributes) + if v.is_primitive] + self.model_selected[:] = vars[:6] + self.model_other[:] = vars[6:] + self.model_selected[:], self.model_other[:] = settings(data) + self._selection = np.zeros(len(data), dtype=np.uint8) + self.invalidate_plot() + else: + self.data = None + + @Inputs.data_subset + def set_subset_data(self, subset): + """ + Set the supplementary input subset dataset. + + Args: + subset (Orange.data.table): subset of data instances + """ + self.subset_data = subset + self._subset_mask = None + self.controls.graph.alpha_value.setEnabled(subset is None) + + def handleNewSignals(self): + if self.data is not None: + self._clear_plot() + if self.subset_data is not None and self._subset_mask is None: + dataids = self.data.ids.ravel() + subsetids = np.unique(self.subset_data.ids) + self._subset_mask = np.in1d( + dataids, subsetids, assume_unique=True) + self.setup_plot(reset_view=True) + self.cb_class_density.setEnabled(self.graph.can_draw_density()) + else: + self.init_attr_values() + self.graph.new_data(None) + self._vizrank_color_change() + self.commit() + + def customEvent(self, event): + if event.type() == OWRadviz.ReplotRequest: + self.__replot_requested = False + self._clear_plot() + self.setup_plot(reset_view=True) + else: + super().customEvent(event) + + def closeContext(self): + self.variable_state = VariablesSelection.encode_var_state( + [list(self.model_selected), list(self.model_other)] + ) + super().closeContext() + + def prepare_radviz_data(self, variables): + ec, points, valid_mask = radviz(self.data, variables, self.plotdata.points) + self.plotdata.embedding_coords = ec + self.plotdata.points = points + self.plotdata.valid_mask = valid_mask + + def setup_plot(self, reset_view=False): + if self.data is None: + return + self.graph.jitter_continuous = True + self.__replot_requested = False + + variables = list(self.model_selected) + if len(variables) < 2: + self.Warning.no_features() + self.graph.new_data(None) + return + + self.Warning.clear() + self.prepare_radviz_data(variables) + + if self.plotdata.embedding_coords is None: + return + + self.plotdata.circle = self._circle + if reset_view: + self.viewbox.setRange(RANGE) + self.viewbox.setAspectLocked(True, 1) + domain = self.data.domain + new_metas = domain.metas + (self.variable_x, self.variable_y) + domain = Domain(attributes=domain.attributes, + class_vars=domain.class_vars, + metas=new_metas) + mask = self.plotdata.valid_mask + array = np.zeros((len(self.data), 2), dtype=np.float) + array[mask] = self.plotdata.embedding_coords + data = Table.from_numpy( + domain, X=self.data.X, Y=self.data.Y, metas=np.hstack((self.data.metas, array))) + subset_data = data[self._subset_mask & mask]\ + if self._subset_mask is not None and len(self._subset_mask) else None + self.plotdata.data = data + self.graph.new_data(data[mask], subset_data) + if self._selection is not None: + self.graph.selection = self._selection[self.plotdata.valid_mask] + self.graph.update_data(self.variable_x, self.variable_y, reset_view=reset_view) + self.graph.plot_widget.addItem(self.plotdata.circle) + self.graph.scatterplot_points = ScatterPlotItem( + x=self.plotdata.points[:, 0], + y=self.plotdata.points[:, 1] + ) + self._update_points_labels() + self.graph.plot_widget.addItem(self.graph.scatterplot_points) + + def randomize_indices(self): + ec = self.plotdata.embedding_coords + self.plotdata.rand = np.random.choice(len(ec), MAX_POINTS, replace=False) \ + if len(ec) > MAX_POINTS else None + + def manual_move(self): + self.__replot_requested = False + + if self.plotdata.rand is not None: + rand = self.plotdata.rand + valid_mask = self.plotdata.valid_mask + data = self.data[valid_mask] + selection = self._selection[valid_mask] + selection = selection[rand] + ec, _, valid_mask = radviz(data, list(self.model_selected), self.plotdata.points) + assert sum(valid_mask) == len(data) + data = data[rand] + ec = ec[rand] + data_x = data.X + data_y = data.Y + data_metas = data.metas + else: + self.prepare_radviz_data(list(self.model_selected)) + ec = self.plotdata.embedding_coords + valid_mask = self.plotdata.valid_mask + data_x = self.data.X[valid_mask] + data_y = self.data.Y[valid_mask] + data_metas = self.data.metas[valid_mask] + selection = self._selection[valid_mask] + + attributes = (self.variable_x, self.variable_y) + self.data.domain.attributes + domain = Domain(attributes=attributes, + class_vars=self.data.domain.class_vars, + metas=self.data.domain.metas) + data = Table.from_numpy(domain, X=np.hstack((ec, data_x)), Y=data_y, metas=data_metas) + self.graph.new_data(data, None) + self.graph.selection = selection + self.graph.update_data(self.variable_x, self.variable_y, reset_view=False) + self.graph.plot_widget.addItem(self.plotdata.circle) + self.graph.scatterplot_points = ScatterPlotItem( + x=self.plotdata.points[:, 0], y=self.plotdata.points[:, 1]) + self._update_points_labels() + self.graph.plot_widget.addItem(self.graph.scatterplot_points) + + def _update_points_labels(self): + if self.plotdata.points is None: + return + for point_label in self.plotdata.point_labels: + self.graph.plot_widget.removeItem(point_label) + self.plotdata.point_labels = [] + sx, sy = self.graph.view_box.viewPixelSize() + + for row in self.plotdata.points: + ti = TextItem() + metrics = QFontMetrics(ti.textItem.font()) + text_width = ((RANGE.width())/2. - np.abs(row[0])) / sx + name = row[2].name + ti.setText(name) + ti.setTextWidth(text_width) + ti.setColor(QColor(0, 0, 0)) + br = ti.boundingRect() + width = metrics.width(name) if metrics.width(name) < br.width() else br.width() + width = sx * (width + 5) + height = sy * br.height() + ti.setPos(row[0] - (row[0] < 0) * width, row[1] + (row[1] > 0) * height) + self.plotdata.point_labels.append(ti) + self.graph.plot_widget.addItem(ti) + + def _update_jitter(self): + self.invalidate_plot() + + def reset_graph_data(self, *_): + if self.data is not None: + self.graph.rescale_data() + self._update_graph() + + def _update_graph(self, reset_view=True, **_): + self.graph.zoomStack = [] + if self.graph.data is None: + return + self.graph.update_data(self.variable_x, self.variable_y, reset_view) + + def update_density(self): + self._update_graph(reset_view=False) + + def selection_changed(self): + if self.graph.selection is not None: + self._selection[self.plotdata.valid_mask] = self.graph.selection + self.commit() + + def prepare_data(self): + pass + + def commit(self): + selected = annotated = components = None + graph = self.graph + if self.plotdata.data is not None: + name = self.data.name + data = self.plotdata.data + mask = self.plotdata.valid_mask.astype(int) + mask[mask == 1] = graph.selection if graph.selection is not None \ + else [False * len(mask)] + selection = np.array([], dtype=np.uint8) if mask is None else np.flatnonzero(mask) + if len(selection): + selected = data[selection] + selected.name = name + ": selected" + selected.attributes = self.data.attributes + if graph.selection is not None and np.max(graph.selection) > 1: + annotated = create_groups_table(data, mask) + else: + annotated = create_annotated_table(data, selection) + annotated.attributes = self.data.attributes + annotated.name = name + ": annotated" + + comp_domain = Domain( + self.plotdata.points[:, 2], + metas=[StringVariable(name='component')]) + + metas = np.array([["RX"], ["RY"], ["angle"]]) + angle = np.arctan2(np.array(self.plotdata.points[:, 1].T, dtype=float), + np.array(self.plotdata.points[:, 0].T, dtype=float)) + components = Table.from_numpy( + comp_domain, + X=np.row_stack((self.plotdata.points[:, :2].T, angle)), + metas=metas) + components.name = name + ": components" + + self.Outputs.selected_data.send(selected) + self.Outputs.annotated_data.send(annotated) + self.Outputs.components.send(components) + + def send_report(self): + if self.data is None: + return + + def name(var): + return var and var.name + + caption = report.render_items_vert(( + ("Color", name(self.graph.attr_color)), + ("Label", name(self.graph.attr_label)), + ("Shape", name(self.graph.attr_shape)), + ("Size", name(self.graph.attr_size)), + ("Jittering", self.graph.jitter_size != 0 and "{} %".format(self.graph.jitter_size)))) + self.report_plot() + if caption: + self.report_caption(caption) + + +def add_arc(angle, col, dangle=5): + if col: + color = QColor(128, 128, 128) # gray + else: + color = QColor(0, 0, 0) # black + angle_d = np.rad2deg(angle) + angle_2 = 90 - angle_d - dangle + angle_1 = 270 - angle_d + dangle + dangle = np.deg2rad(dangle) + arrow1 = pg.ArrowItem(parent=None, angle=angle_1, brush=color, pen=pg.mkPen(color, width=1)) + arrow1.setPos(np.cos(angle - dangle), np.sin(angle - dangle)) + arrow2 = pg.ArrowItem(parent=None, angle=angle_2, brush=color, pen=pg.mkPen(color, width=1)) + arrow2.setPos(np.cos(angle + dangle), np.sin(angle + dangle)) + arc_x = np.fromfunction(lambda i: np.cos((angle - dangle) + (2 * dangle) * i / 120.), (121,), + dtype=int) + arc_y = np.fromfunction(lambda i: np.sin((angle - dangle) + (2 * dangle) * i / 120.), (121,), + dtype=int) + arc = pg.PlotCurveItem( + x=arc_x, y=arc_y, + pen=pg.mkPen(color, width=1), + antialias=False + ) + return [arc, arrow1, arrow2] + + +def main(argv=None): + import sys + import sip + + argv = sys.argv[1:] if argv is None else argv + if argv: + filename = argv[0] + else: + filename = "heart_disease" + + data = Table(filename) + + app = QApplication([]) + w = OWRadviz() + w.set_data(data) + w.set_subset_data(data[::10]) + w.handleNewSignals() + w.show() + w.raise_() + r = app.exec() + w.set_data(None) + w.saveSettings() + sip.delete(w) + del w + return r + + +if __name__ == "__main__": + import sys + sys.exit(main()) From 3da84e3e3c7322acd08876245099b1b4ce1bb62e Mon Sep 17 00:00:00 2001 From: Jernej Urankar Date: Wed, 6 Sep 2017 16:27:29 +0200 Subject: [PATCH 4/6] Radviz: documentation --- doc/visual-programming/source/index.rst | 1 + .../source/widgets/visualize/icons/radviz.png | Bin 0 -> 1470 bytes .../visualize/images/Radviz-Brown-2.png | Bin 0 -> 59667 bytes .../widgets/visualize/images/Radviz-Brown.png | Bin 0 -> 51774 bytes .../source/widgets/visualize/radviz.rst | 95 ++++++++++++++++++ 5 files changed, 96 insertions(+) create mode 100644 doc/visual-programming/source/widgets/visualize/icons/radviz.png create mode 100644 doc/visual-programming/source/widgets/visualize/images/Radviz-Brown-2.png create mode 100644 doc/visual-programming/source/widgets/visualize/images/Radviz-Brown.png create mode 100644 doc/visual-programming/source/widgets/visualize/radviz.rst diff --git a/doc/visual-programming/source/index.rst b/doc/visual-programming/source/index.rst index fe333e6179b..095c03e2738 100644 --- a/doc/visual-programming/source/index.rst +++ b/doc/visual-programming/source/index.rst @@ -72,6 +72,7 @@ Visualize widgets/visualize/treeviewer widgets/visualize/nomogram widgets/visualize/freeviz + widgets/visualize/radviz Model diff --git a/doc/visual-programming/source/widgets/visualize/icons/radviz.png b/doc/visual-programming/source/widgets/visualize/icons/radviz.png new file mode 100644 index 0000000000000000000000000000000000000000..436a8390b6818fb885ad67ac90aceeae089785a9 GIT binary patch literal 1470 zcmV;v1ws0WP)B6w5Dl>rlzTB$gBn}oXMFqa0C=l z20?O&uYpBbvC1tTLP7Fw`|Rvs4@ClnSH zbA_?H<9`dV^1!<|@$n}QtsfH`3-Wd5be(Yf_U#iCfN}HYY%JctzwA{l$2L7Z11tcZ z0YtA|i~Ea=7gT%zgk(--`goJoRN3TV7brtsR-G|{}69xwdaJIf4 zjSY=37!269ZF|5>xB~F8dX^%bKmQxd=22v1WFkMm0AXQa3O&6(o^xJa9t+Znrlw11 zX=z4(e?NBYcowY2d$B$P_ zzmFVwpRc;Kv<#Y*!6rNRBAOJBL^aT>Wc+j z``mYs)z6?)1!XPZd zBy9Pdmm+lX?~V(GRv>c{xO#Z@&IY8h?Gy8(y;@IwXC$4#|W~J{*b~ zaJarnSlAkjjhPV{6~*OOUfc7a(wB57BNUV<%gLL*oCuqI$miT@fbMj<2U29)#FNB~ z_}VEaYrmC#mzBS&xMRqNq6QqSDv9Z`pshG-vvHZg#5v;9m&zrUkIPwJ2XYL;By92_ z*LBsvQc50U%|`bhH}UhCIxg>iv5e3C_`^vlVj2rXQXMc`(m(aRtB^xkFF`&WiccUL zu(5_><;s=Fd$Pc7+~2pCQ^^aZiaOY~{TWx?4Y=6h~+iy3gbad^1E+U8BL&RF>!K0ZFK&(@ox6d_<-Z2SULB|^hUqmk-;y~nd`rfLu>@_trZNa?VPLI<{)&KoG|4V=Y Y0O!Kj;cWb64*&oF07*qoM6N<$f}c#nIsgCw literal 0 HcmV?d00001 diff --git a/doc/visual-programming/source/widgets/visualize/images/Radviz-Brown-2.png b/doc/visual-programming/source/widgets/visualize/images/Radviz-Brown-2.png new file mode 100644 index 0000000000000000000000000000000000000000..80f937b6f100a79e6da8f74072b983f1dc95a632 GIT binary patch literal 59667 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

%uzy+U^x80Hrw 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 sn!)Su@Be-F<%fSq! Date: Fri, 13 Oct 2017 12:32:58 +0200 Subject: [PATCH 5/6] Radviz: add tests --- .../widgets/visualize/tests/test_owradviz.py | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 Orange/widgets/visualize/tests/test_owradviz.py diff --git a/Orange/widgets/visualize/tests/test_owradviz.py b/Orange/widgets/visualize/tests/test_owradviz.py new file mode 100644 index 00000000000..e88510f4cb2 --- /dev/null +++ b/Orange/widgets/visualize/tests/test_owradviz.py @@ -0,0 +1,76 @@ +# Test methods with long descriptive names can omit docstrings +# pylint: disable=missing-docstring +from AnyQt.QtCore import QRectF, QPointF + +from Orange.data import Table, Domain +from Orange.widgets.tests.base import WidgetTest, WidgetOutputsTestMixin, \ + datasets +from Orange.widgets.visualize.owradviz import OWRadviz + + +class TestOWFreeViz(WidgetTest, WidgetOutputsTestMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + WidgetOutputsTestMixin.init(cls) + + cls.signal_name = "Data" + cls.signal_data = cls.data + cls.same_input_output_domain = False + cls.heart_disease = Table("heart_disease") + + def setUp(self): + self.widget = self.create_widget(OWRadviz) + + def test_points_combo_boxes(self): + self.send_signal(self.widget.Inputs.data, self.heart_disease) + graph = self.widget.controls.graph + self.assertEqual(len(graph.attr_color.model()), 17) + self.assertEqual(len(graph.attr_shape.model()), 11) + self.assertEqual(len(graph.attr_size.model()), 8) + self.assertEqual(len(graph.attr_label.model()), 17) + + def test_ugly_datasets(self): + self.send_signal(self.widget.Inputs.data, Table(datasets.path("testing_dataset_cls"))) + self.send_signal(self.widget.Inputs.data, Table(datasets.path("testing_dataset_reg"))) + + def test_btn_vizrank(self): + # TODO: fix this + w = self.widget + def assertEnabled(data, is_enabled): + self.send_signal(w.Inputs.data, data) + self.assertEqual(is_enabled, w.btn_vizrank.isEnabled()) + + data = self.data + for data, is_enabled in zip([data[:, :3], data, None], [False, False, False]): + assertEnabled(data, is_enabled) + + def _select_data(self): + self.widget.graph.select_by_rectangle(QRectF(QPointF(-20, -20), QPointF(20, 20))) + return self.widget.graph.get_selection() + + def test_subset_data(self): + w = self.widget + data = Table("iris") + self.send_signal(w.Inputs.data, data) + self.send_signal(w.Inputs.data_subset, data[::30]) + + def test_no_features(self): + w = self.widget + data = Table("iris") + domain = Domain(attributes=data.domain.attributes[:1], class_vars=data.domain.class_vars) + data2 = data.transform(domain) + self.assertFalse(w.Error.no_features.is_shown()) + self.send_signal(w.Inputs.data, data2) + self.assertTrue(w.Error.no_features.is_shown()) + self.send_signal(w.Inputs.data, None) + self.assertFalse(w.Error.no_features.is_shown()) + + def test_not_enough_instances(self): + w = self.widget + data = Table("iris") + self.assertFalse(w.Error.no_instances.is_shown()) + self.send_signal(w.Inputs.data, data[:1]) + self.assertTrue(w.Error.no_instances.is_shown()) + self.send_signal(w.Inputs.data, data) + self.assertFalse(w.Error.no_instances.is_shown()) From b2de1a51df0623cc603a2cc3db76353ea00e56ab Mon Sep 17 00:00:00 2001 From: Jernej Urankar Date: Fri, 15 Dec 2017 15:39:33 +0100 Subject: [PATCH 6/6] Radviz: various fixes: * circle * message * density * VizRank: maximum number of features * classes not as default as selected * use first 5 features * do not use plotdata.circle * VizRank: fix combinations --- Orange/widgets/visualize/owradviz.py | 60 ++++++++++++---------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/Orange/widgets/visualize/owradviz.py b/Orange/widgets/visualize/owradviz.py index 534c352a350..b242c7c99ed 100644 --- a/Orange/widgets/visualize/owradviz.py +++ b/Orange/widgets/visualize/owradviz.py @@ -10,7 +10,8 @@ from AnyQt.QtGui import QStandardItem, QColor, QFontMetrics, QCursor from AnyQt.QtCore import Qt, QEvent, QSize, QRectF, QPoint from AnyQt.QtCore import pyqtSignal as Signal -from AnyQt.QtWidgets import qApp, QSizePolicy, QApplication, QToolTip, QGraphicsSceneMouseEvent +from AnyQt.QtWidgets import qApp, QSizePolicy, QApplication, QToolTip, QGraphicsSceneMouseEvent, \ + QGraphicsEllipseItem import pyqtgraph as pg from pyqtgraph.graphicsItems.ScatterPlotItem import ScatterPlotItem @@ -39,7 +40,7 @@ class RadvizVizRank(VizRankDialog, OWComponent): captionTitle = "Score Plots" - n_attrs = settings.Setting(6) + n_attrs = settings.Setting(3) minK = 10 attrsSelected = Signal([]) @@ -58,15 +59,12 @@ def __init__(self, master): box = gui.hBox(self) self.n_attrs_spin = gui.spin( - box, self, "n_attrs", 4, max_n_attrs, label="Number of variables: ", + box, self, "n_attrs", 3, max_n_attrs, label="Maximum number of variables: ", controlWidth=50, alignment=Qt.AlignRight, callback=self._n_attrs_changed) gui.rubber(box) self.last_run_n_attrs = None self.attr_color = master.graph.attr_color - self.attr_ordering = None - self.last_run_n_attrs = None - self.attr_color = master.graph.attr_color self.data = None self.valid_data = None @@ -146,7 +144,7 @@ def on_selection_changed(self, selected, deselected): def iterate_states(self, state): if state is None: # on the first call, compute order self.attrs = self._compute_attr_order() - state = list(range(self.n_attrs)) + state = list(range(3)) else: state = list(state) @@ -159,7 +157,10 @@ def combinations(n, s): break s[up] = up if s[-1] == n: - break + if len(s) < self.n_attrs: + s = list(range(len(s) + 1)) + else: + break for c in combinations(len(self.attrs), state): for p in islice(permutations(c[1:]), factorial(len(c) - 1) // 2): @@ -283,11 +284,11 @@ def hide_axes(self): self.plot_widget.hideAxis(axis) def update_data(self, attr_x, attr_y, reset_view=True): - super().update_data(attr_x, attr_y, reset_view) - self.hide_axes() if reset_view: self.view_box.setRange(RANGE, padding=0.025) self.view_box.setAspectLocked(True, 1) + super().update_data(attr_x, attr_y, reset_view=False) + self.hide_axes() def show_arc_arrow(self, x=None, y=None, point_i=None): def remove_arc_arrows(): @@ -366,7 +367,6 @@ def help_event(self, event): RANGE = QRectF(-1.2, -1.05, 2.4, 2.1) -MAX_ANCHORS = 16 MAX_POINTS = 100 class OWRadviz(widget.OWWidget): @@ -404,7 +404,7 @@ class Information(widget.OWWidget.Information): sql_sampled_data = widget.Msg("Data has been sampled") class Warning(widget.OWWidget.Warning): - no_features = widget.Msg("At least 2 features has to be chosen") + no_features = widget.Msg("At least 2 features have to be chosen") class Error(widget.OWWidget.Error): sparse_data = widget.Msg("Sparse data is not supported") @@ -470,12 +470,9 @@ def __init__(self): self.graph.zoom_actions(self) - self._circle = pg.PlotCurveItem( - x=np.fromfunction(lambda i: np.cos(2. * np.pi * i / 120.), (121,), dtype=int), - y=np.fromfunction(lambda i: np.sin(2. * np.pi * i / 120.), (121,), dtype=int), - pen=pg.mkPen(QColor(0, 0, 0), width=2), - antialias=False - ) + self._circle = QGraphicsEllipseItem() + self._circle.setRect(QRectF(-1., -1., 2., 2.)) + self._circle.setPen(pg.mkPen(QColor(0, 0, 0), width=2)) def resizeEvent(self, event): self._update_points_labels() @@ -500,7 +497,6 @@ def _new_plotdata(self): valid_mask=None, embedding_coords=None, points=None, - circle=None, arcarrows=[], point_labels=[], rand=None, @@ -553,7 +549,7 @@ def _vizrank_color_change(self): and not np.isnan(self.data.get_column_view(attr_color)[0].astype(float)).all()) if is_enabled and (attr_color is None or (attr_color is not None and not attr_color.is_discrete)): - self.btn_vizrank.setToolTip("Discrete color variable has to be selected.") + self.btn_vizrank.setToolTip("Categorical color variable has to be selected.") else: self.btn_vizrank.setToolTip("") self.vizrank.initialize() @@ -638,10 +634,10 @@ def are_instances(data): self.data = data self.init_attr_values() domain = data.domain - vars = [v for v in chain(domain.class_vars, domain.metas, domain.attributes) - if v.is_primitive] - self.model_selected[:] = vars[:6] - self.model_other[:] = vars[6:] + vars = [v for v in chain(domain.metas, domain.attributes) + if v.is_primitive()] + self.model_selected[:] = vars[:5] + self.model_other[:] = vars[5:] + list(domain.class_vars) self.model_selected[:], self.model_other[:] = settings(data) self._selection = np.zeros(len(data), dtype=np.uint8) self.invalidate_plot() @@ -696,7 +692,7 @@ def prepare_radviz_data(self, variables): self.plotdata.points = points self.plotdata.valid_mask = valid_mask - def setup_plot(self, reset_view=False): + def setup_plot(self, reset_view=True): if self.data is None: return self.graph.jitter_continuous = True @@ -714,10 +710,6 @@ def setup_plot(self, reset_view=False): if self.plotdata.embedding_coords is None: return - self.plotdata.circle = self._circle - if reset_view: - self.viewbox.setRange(RANGE) - self.viewbox.setAspectLocked(True, 1) domain = self.data.domain new_metas = domain.metas + (self.variable_x, self.variable_y) domain = Domain(attributes=domain.attributes, @@ -735,7 +727,7 @@ def setup_plot(self, reset_view=False): if self._selection is not None: self.graph.selection = self._selection[self.plotdata.valid_mask] self.graph.update_data(self.variable_x, self.variable_y, reset_view=reset_view) - self.graph.plot_widget.addItem(self.plotdata.circle) + self.graph.plot_widget.addItem(self._circle) self.graph.scatterplot_points = ScatterPlotItem( x=self.plotdata.points[:, 0], y=self.plotdata.points[:, 1] @@ -780,8 +772,8 @@ def manual_move(self): data = Table.from_numpy(domain, X=np.hstack((ec, data_x)), Y=data_y, metas=data_metas) self.graph.new_data(data, None) self.graph.selection = selection - self.graph.update_data(self.variable_x, self.variable_y, reset_view=False) - self.graph.plot_widget.addItem(self.plotdata.circle) + self.graph.update_data(self.variable_x, self.variable_y, reset_view=True) + self.graph.plot_widget.addItem(self._circle) self.graph.scatterplot_points = ScatterPlotItem( x=self.plotdata.points[:, 0], y=self.plotdata.points[:, 1]) self._update_points_labels() @@ -823,10 +815,10 @@ def _update_graph(self, reset_view=True, **_): self.graph.zoomStack = [] if self.graph.data is None: return - self.graph.update_data(self.variable_x, self.variable_y, reset_view) + self.graph.update_data(self.variable_x, self.variable_y, reset_view=reset_view) def update_density(self): - self._update_graph(reset_view=False) + self._update_graph(reset_view=True) def selection_changed(self): if self.graph.selection is not None: