Skip to content

Commit

Permalink
Merge pull request #3436 from VesnaT/resize
Browse files Browse the repository at this point in the history
[ENH] OWScatterPlotBase: Animate dot resize
  • Loading branch information
janezd authored Dec 4, 2018
2 parents cdfa54f + 9691941 commit 1602d56
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 7 deletions.
51 changes: 46 additions & 5 deletions Orange/widgets/visualize/owscatterplotgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import numpy as np

from AnyQt.QtCore import Qt, QRectF, QSize
from AnyQt.QtCore import Qt, QRectF, QSize, QTimer
from AnyQt.QtGui import (
QStaticText, QColor, QPen, QBrush, QPainterPath, QTransform, QPainter
)
Expand Down Expand Up @@ -405,6 +405,8 @@ def __init__(self, scatter_widget, parent=None, view_box=ViewBox):
self.plot_widget.scene().installEventFilter(self._tooltip_delegate)
self.view_box.sigTransformChanged.connect(self.update_density)

self.timer = None

def _create_legend(self, anchor):
legend = LegendItem()
legend.setParentItem(self.plot_widget.getViewBox())
Expand Down Expand Up @@ -485,6 +487,9 @@ def clear(self):
self.plot_widget.clear()

self.density_img = None
if self.timer is not None and self.timer.isActive():
self.timer.stop()
self.timer = None
self.scatterplot_item = None
self.scatterplot_item_sel = None
self.labels = []
Expand Down Expand Up @@ -704,8 +709,10 @@ def get_sizes(self):
self.MinShapeSize + (5 + self.point_width) * 0.5)
size_column = self._filter_visible(size_column)
size_column = size_column.copy()
size_column -= np.nanmin(size_column)
mx = np.nanmax(size_column)
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=RuntimeWarning)
size_column -= np.nanmin(size_column)
mx = np.nanmax(size_column)
if mx > 0:
size_column /= mx
else:
Expand All @@ -725,8 +732,42 @@ def update_sizes(self):
size_imputer = getattr(
self.master, "impute_sizes", self.default_impute_sizes)
size_imputer(size_data)
self.scatterplot_item.setSize(size_data)
self.scatterplot_item_sel.setSize(size_data + SELECTION_WIDTH)

if self.timer is not None and self.timer.isActive():
self.timer.stop()
self.timer = None

current_size_data = self.scatterplot_item.data["size"].copy()
diff = size_data - current_size_data
widget = self

class Timeout:
# 0.5 - np.cos(np.arange(0.17, 1, 0.17) * np.pi) / 2
factors = [0.07, 0.26, 0.52, 0.77, 0.95, 1]

def __init__(self):
self._counter = 0

def __call__(self):
factor = self.factors[self._counter]
self._counter += 1
size = current_size_data + diff * factor
if len(self.factors) == self._counter:
widget.timer.stop()
widget.timer = None
size = size_data
widget.scatterplot_item.setSize(size)
widget.scatterplot_item_sel.setSize(size + SELECTION_WIDTH)

if np.sum(current_size_data) / self.n_valid != -1 and np.sum(diff):
# If encountered any strange behaviour when updating sizes,
# implement it with threads
self.timer = QTimer(self.scatterplot_item, interval=50)
self.timer.timeout.connect(Timeout())
self.timer.start()
else:
self.scatterplot_item.setSize(size_data)
self.scatterplot_item_sel.setSize(size_data + SELECTION_WIDTH)

update_point_size = update_sizes # backward compatibility (needed?!)
update_size = update_sizes
Expand Down
18 changes: 16 additions & 2 deletions Orange/widgets/visualize/tests/test_owscatterplotbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

from pyqtgraph import mkPen

from Orange.widgets.tests.base import GuiTest
from Orange.widgets.settings import SettingProvider
from Orange.widgets.tests.base import WidgetTest
from Orange.widgets.utils.colorpalette import ColorPaletteGenerator, \
ContinuousPaletteGenerator, NAN_GREY
from Orange.widgets.visualize.owscatterplotgraph import OWScatterPlotBase, \
Expand All @@ -34,14 +35,17 @@ class MockWidget(OWWidget):
combined_legend = Mock(return_value=False)
selection_changed = Mock(return_value=None)

GRAPH_CLASS = OWScatterPlotBase
graph = SettingProvider(OWScatterPlotBase)

def get_palette(self):
if self.is_continuous_color():
return ContinuousPaletteGenerator(Qt.white, Qt.black, False)
else:
return ColorPaletteGenerator(12)


class TestOWScatterPlotBase(GuiTest):
class TestOWScatterPlotBase(WidgetTest):
def setUp(self):
self.master = MockWidget()
self.graph = OWScatterPlotBase(self.master)
Expand Down Expand Up @@ -160,6 +164,8 @@ def test_sampling(self):
master.get_label_data = lambda: \
np.array([str(x) for x in d], dtype=object)
graph.reset_graph()
self.process_events(until=lambda: not (
self.graph.timer is not None and self.graph.timer.isActive()))

# Check proper sampling
scatterplot_item = graph.scatterplot_item
Expand Down Expand Up @@ -187,6 +193,8 @@ def test_sampling(self):

# Check that sample is extended when sample size is changed
graph.set_sample_size(4)
self.process_events(until=lambda: not (
self.graph.timer is not None and self.graph.timer.isActive()))
scatterplot_item = graph.scatterplot_item
x, y = scatterplot_item.getData()
data = scatterplot_item.data
Expand Down Expand Up @@ -226,6 +234,8 @@ def test_sampling(self):

# Enable sampling when data is already present and not sampled
graph.set_sample_size(3)
self.process_events(until=lambda: not (
self.graph.timer is not None and self.graph.timer.isActive()))
scatterplot_item = graph.scatterplot_item
x, y = scatterplot_item.getData()
data = scatterplot_item.data
Expand Down Expand Up @@ -261,6 +271,8 @@ def test_sampling(self):
np.arange(100, 105, dtype=float))
d = self.xy[0] - 100
graph.reset_graph()
self.process_events(until=lambda: not (
self.graph.timer is not None and self.graph.timer.isActive()))
scatterplot_item = graph.scatterplot_item
x, y = scatterplot_item.getData()
self.assertEqual(len(x), 3)
Expand Down Expand Up @@ -365,6 +377,8 @@ def test_size_with_nans(self):

d[4] = np.nan
graph.update_sizes()
self.process_events(until=lambda: not (
self.graph.timer is not None and self.graph.timer.isActive()))
sizes2 = scatterplot_item.data["size"]

self.assertEqual(sizes[1] - sizes[0], sizes2[1] - sizes2[0])
Expand Down
1 change: 1 addition & 0 deletions Orange/widgets/visualize/utils/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,7 @@ def onDeleteWidget(self):
super().onDeleteWidget()
self.graph.plot_widget.getViewBox().deleteLater()
self.graph.plot_widget.clear()
self.graph.clear()


class OWAnchorProjectionWidget(OWDataProjectionWidget):
Expand Down

0 comments on commit 1602d56

Please sign in to comment.