Skip to content
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

[ENH] Projections: Allow transparent subset #5141

Merged
merged 1 commit into from
Jan 21, 2021
Merged
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
26 changes: 15 additions & 11 deletions Orange/widgets/visualize/owscatterplotgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ def get_size_data(self):

COLOR_NOT_SUBSET = (128, 128, 128, 0)
COLOR_SUBSET = (128, 128, 128, 255)
COLOR_DEFAULT = (128, 128, 128, 0)
COLOR_DEFAULT = (128, 128, 128, 255)

MAX_VISIBLE_LABELS = 500

Expand Down Expand Up @@ -1048,15 +1048,19 @@ def _get_same_colors(self, subset):
"""
color = self.plot_widget.palette().color(OWPalette.Data)
pen = [_make_pen(color, 1.5)] * self.n_shown # use a single QPen instance

# Prepare all brushes; we use the first two or the last
brushes = []
for c in (self.COLOR_SUBSET, self.COLOR_NOT_SUBSET, self.COLOR_DEFAULT):
color = QColor(*c)
if color.alpha():
color.setAlpha(self.alpha_value)
brushes.append(QBrush(color))

if subset is not None:
brush = np.where(
subset,
*(QBrush(QColor(*col))
for col in (self.COLOR_SUBSET, self.COLOR_NOT_SUBSET)))
brush = np.where(subset, *brushes[:2])
else:
color = QColor(*self.COLOR_DEFAULT)
color.setAlpha(self.alpha_value)
brush = [QBrush(color)] * self.n_shown # use a single QBrush instance
brush = brushes[-1:] * self.n_shown # use a single QBrush instance
return pen, brush

def _get_continuous_colors(self, c_data, subset):
Expand Down Expand Up @@ -1102,7 +1106,7 @@ def create_brush(col):

if subset is not None:
brush[:, 3] = 0
brush[subset, 3] = 255
brush[subset, 3] = self.alpha_value

cached_brushes = {}
brush = np.array([reuse(cached_brushes, create_brush, *col)
Expand Down Expand Up @@ -1133,7 +1137,7 @@ def _get_discrete_colors(self, c_data, subset):
pens = np.array(
[_make_pen(col.darker(self.DarkerValue), 1.5) for col in colors])
pen = pens[c_data]
if subset is None and self.alpha_value < 255:
if self.alpha_value < 255:
for col in colors:
col.setAlpha(self.alpha_value)
brushes = np.array([QBrush(col) for col in colors])
Expand Down Expand Up @@ -1504,7 +1508,7 @@ def _update_colored_legend(self, legend, labels, symbols):
for color, label, symbol in zip(colors, labels, symbols):
color = QColor(*color)
pen = _make_pen(color.darker(self.DarkerValue), 1.5)
color.setAlpha(255 if self.subset_is_shown else self.alpha_value)
color.setAlpha(self.alpha_value)
brush = QBrush(color)
legend.addItem(
SymbolItemSample(pen=pen, brush=brush, size=10, symbol=symbol),
Expand Down
15 changes: 15 additions & 0 deletions Orange/widgets/visualize/tests/test_owscatterplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,21 @@ def test_subset_data(self):
self.send_signal(w.Inputs.data_subset, data[::30])
self.assertEqual(len(w.subset_indices), 5)

def test_opacity_warning(self):
data = Table("iris")
w = self.widget
self.send_signal(w.Inputs.data, data)
w.graph.controls.alpha_value.setSliderPosition(10)
self.assertFalse(w.Warning.transparent_subset.is_shown())
self.send_signal(w.Inputs.data_subset, data[::30])
self.assertTrue(w.Warning.transparent_subset.is_shown())
w.graph.controls.alpha_value.setSliderPosition(200)
self.assertFalse(w.Warning.transparent_subset.is_shown())
w.graph.controls.alpha_value.setSliderPosition(10)
self.assertTrue(w.Warning.transparent_subset.is_shown())
self.send_signal(w.Inputs.data_subset, None)
self.assertFalse(w.Warning.transparent_subset.is_shown())

def test_metas_zero_column(self):
"""
Prevent crash when metas column is zero.
Expand Down
6 changes: 3 additions & 3 deletions Orange/widgets/visualize/tests/test_owscatterplotbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -614,9 +614,9 @@ def run_tests():
self.assertEqual(brushes[0].color().alpha(), 0)
self.assertEqual(brushes[1].color().alpha(), 0)
self.assertEqual(brushes[4].color().alpha(), 0)
self.assertEqual(brushes[5].color().alpha(), 255)
self.assertEqual(brushes[6].color().alpha(), 255)
self.assertEqual(brushes[7].color().alpha(), 255)
self.assertEqual(brushes[5].color().alpha(), 123)
self.assertEqual(brushes[6].color().alpha(), 123)
self.assertEqual(brushes[7].color().alpha(), 123)

graph = self.graph

Expand Down
9 changes: 8 additions & 1 deletion Orange/widgets/visualize/utils/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ def can_draw_density(self):

def colors_changed(self):
self.graph.update_colors()
self._update_opacity_warning()
self.cb_class_density.setEnabled(self.can_draw_density())

# Labels
Expand Down Expand Up @@ -378,6 +379,8 @@ class Warning(OWProjectionWidgetBase.Warning):
"input data")
subset_independent = Msg(
"No subset data instances appear in input data")
transparent_subset = Msg(
"Increase opacity if subset is difficult to see")

settingsHandler = DomainContextHandler()
selection = Setting(None, schema_only=True)
Expand Down Expand Up @@ -473,7 +476,6 @@ def enable_controls(self):
@check_sql_input
def set_subset_data(self, subset):
self.subset_data = subset
self.controls.graph.alpha_value.setEnabled(subset is None)

def handleNewSignals(self):
self._handle_subset_data()
Expand All @@ -482,6 +484,7 @@ def handleNewSignals(self):
self.setup_plot()
else:
self.graph.update_point_props()
self._update_opacity_warning()
self.unconditional_commit()

def _handle_subset_data(self):
Expand All @@ -497,6 +500,10 @@ def _handle_subset_data(self):
elif self.subset_indices - ids:
self.Warning.subset_not_subset()

def _update_opacity_warning(self):
self.Warning.transparent_subset(
shown=self.subset_indices and self.graph.alpha_value < 128)

def set_input_summary(self, data):
summary = len(data) if data else self.info.NoInput
detail = format_summary_details(data) if data else ""
Expand Down