Skip to content

Commit 5a46b6c

Browse files
committed
Scatterplot: Use opacity for contrast
1 parent 3634e37 commit 5a46b6c

File tree

1 file changed

+53
-41
lines changed

1 file changed

+53
-41
lines changed

Orange/widgets/visualize/owscatterplotgraph.py

Lines changed: 53 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -534,9 +534,7 @@ def get_size_data(self):
534534
DarkerValue = 120
535535
UnknownColor = (168, 50, 168)
536536

537-
COLOR_NOT_SUBSET = (128, 128, 128, 0)
538-
COLOR_SUBSET = (128, 128, 128, 255)
539-
COLOR_DEFAULT = (128, 128, 128, 255)
537+
COLOR_DEFAULT = (128, 128, 128)
540538

541539
MAX_VISIBLE_LABELS = 500
542540

@@ -1025,7 +1023,7 @@ def get_colors(self):
10251023
else:
10261024
return self._get_discrete_colors(c_data, subset)
10271025

1028-
def _get_same_colors(self, subset):
1026+
def _get_same_colors(self, subset, color=COLOR_DEFAULT):
10291027
"""
10301028
Return the same pen for all points while the brush color depends
10311029
upon whether the point is in the subset or not
@@ -1038,21 +1036,17 @@ def _get_same_colors(self, subset):
10381036
Returns:
10391037
(tuple): a list of pens and list of brushes
10401038
"""
1041-
color = self.plot_widget.palette().color(OWPalette.Data)
1042-
pen = [_make_pen(color, 1.5)] * self.n_shown # use a single QPen instance
1043-
1044-
# Prepare all brushes; we use the first two or the last
1045-
brushes = []
1046-
for c in (self.COLOR_SUBSET, self.COLOR_NOT_SUBSET, self.COLOR_DEFAULT):
1047-
color = QColor(*c)
1048-
if color.alpha():
1049-
color.setAlpha(self.alpha_value)
1050-
brushes.append(QBrush(color))
10511039

10521040
if subset is not None:
1053-
brush = np.where(subset, *brushes[:2])
1041+
colors = [QColor(*color, alpha)
1042+
for alpha in self._alpha_for_subsets()]
1043+
brushes = [QBrush(color) for color in colors]
1044+
brush = np.where(subset, *brushes)
10541045
else:
1055-
brush = brushes[-1:] * self.n_shown # use a single QBrush instance
1046+
qcolor = QColor(*color, self.alpha_value)
1047+
brush = np.full(self.n_shown, QBrush(qcolor))
1048+
qcolor = QColor(*color, self.alpha_value)
1049+
pen = [_make_pen(qcolor, 1.5)] * self.n_shown
10561050
return pen, brush
10571051

10581052
def _get_continuous_colors(self, c_data, subset):
@@ -1066,18 +1060,18 @@ def _get_continuous_colors(self, c_data, subset):
10661060

10671061
if np.isnan(c_data).all():
10681062
self.palette = palette
1069-
return self._get_continuous_nan_colors(len(c_data))
1063+
return self._get_same_colors(subset, self.palette.nan_color)
10701064

10711065
self.scale = DiscretizedScale(np.nanmin(c_data), np.nanmax(c_data))
10721066
bins = self.scale.get_bins()
10731067
self.palette = \
10741068
colorpalettes.BinnedContinuousPalette.from_palette(palette, bins)
10751069
colors = self.palette.values_to_colors(c_data)
1076-
brush = np.hstack(
1077-
(colors,
1078-
np.full((len(c_data), 1), self.alpha_value, dtype=np.ubyte)))
1079-
pen = (colors.astype(dtype=float) * 100 / self.DarkerValue
1080-
).astype(np.ubyte)
1070+
alphas = np.full((len(c_data), 1), self.alpha_value, dtype=np.ubyte)
1071+
brush = np.hstack((colors, alphas))
1072+
pen = np.hstack(
1073+
((colors.astype(dtype=float) * 100 / self.DarkerValue).astype(np.ubyte),
1074+
alphas))
10811075

10821076
# Reuse pens and brushes with the same colors because PyQtGraph then
10831077
# builds smaller pixmap atlas, which makes the drawing faster
@@ -1093,27 +1087,21 @@ def create_pen(col):
10931087
def create_brush(col):
10941088
return QBrush(QColor(*col))
10951089

1096-
cached_pens = {}
1097-
pen = [reuse(cached_pens, create_pen, *col) for col in pen.tolist()]
1098-
10991090
if subset is not None:
1091+
alpha_subset, alpha_unset = self._alpha_for_subsets()
11001092
brush[:, 3] = 0
1101-
brush[subset, 3] = self.alpha_value
1093+
brush[subset, 3] = alpha_subset
1094+
pen[:, 3] = alpha_unset
1095+
brush[subset, 3] = alpha_subset
11021096

1097+
cached_pens = {}
1098+
pen = [reuse(cached_pens, create_pen, *col) for col in pen.tolist()]
11031099
cached_brushes = {}
11041100
brush = np.array([reuse(cached_brushes, create_brush, *col)
11051101
for col in brush.tolist()])
11061102

11071103
return pen, brush
11081104

1109-
def _get_continuous_nan_colors(self, n):
1110-
nan_color = QColor(*self.palette.nan_color)
1111-
nan_pen = _make_pen(nan_color.darker(1.2), 1.5)
1112-
pen = np.full(n, nan_pen)
1113-
nan_brush = QBrush(nan_color)
1114-
brush = np.full(n, nan_brush)
1115-
return pen, brush
1116-
11171105
def _get_discrete_colors(self, c_data, subset):
11181106
"""
11191107
Return the pens and colors whose color represent an index into
@@ -1126,20 +1114,44 @@ def _get_discrete_colors(self, c_data, subset):
11261114
c_data[np.isnan(c_data)] = len(self.palette)
11271115
c_data = c_data.astype(int)
11281116
colors = self.palette.qcolors_w_nan
1129-
pens = np.array(
1130-
[_make_pen(col.darker(self.DarkerValue), 1.5) for col in colors])
1131-
pen = pens[c_data]
1132-
if self.alpha_value < 255:
1117+
if subset is None:
11331118
for col in colors:
11341119
col.setAlpha(self.alpha_value)
1135-
brushes = np.array([QBrush(col) for col in colors])
1136-
brush = brushes[c_data]
1120+
pens = np.array(
1121+
[_make_pen(col.darker(self.DarkerValue), 1.5)
1122+
for col in colors])
1123+
pen = pens[c_data]
1124+
brushes = np.array([QBrush(col) for col in colors])
1125+
brush = brushes[c_data]
1126+
else:
1127+
subset_colors = [QColor(col) for col in colors]
1128+
alpha_subset, alpha_unset = self._alpha_for_subsets()
1129+
for col in subset_colors:
1130+
col.setAlpha(alpha_subset)
1131+
for col in colors:
1132+
col.setAlpha(alpha_unset)
11371133

1138-
if subset is not None:
1134+
pens, subset_pens = (
1135+
np.array(
1136+
[_make_pen(col.darker(self.DarkerValue), 1.5)
1137+
for col in cols])
1138+
for cols in (colors, subset_colors))
1139+
pen = np.where(subset, subset_pens[c_data], pens[c_data])
1140+
1141+
brushes = np.array([QBrush(col) for col in subset_colors])
1142+
brush = brushes[c_data]
11391143
black = np.full(len(brush), QBrush(QColor(0, 0, 0, 0)))
11401144
brush = np.where(subset, brush, black)
11411145
return pen, brush
11421146

1147+
def _alpha_for_subsets(self):
1148+
a, b, c = 1.2, -3.2, 3
1149+
x = self.alpha_value / 255
1150+
alpha_subset = 31 + int(224 * (a * x ** 3 + b * x ** 2 + c * x))
1151+
x = 1 - x
1152+
alpha_unset = int(255 - 224 * (a * x ** 3 + b * x ** 2 + c * x))
1153+
return alpha_subset, alpha_unset
1154+
11431155
def update_colors(self):
11441156
"""
11451157
Trigger an update of point colors

0 commit comments

Comments
 (0)