Skip to content

Commit 3130077

Browse files
committed
Indicate overlap by point size.
1 parent b5ad055 commit 3130077

File tree

1 file changed

+31
-10
lines changed

1 file changed

+31
-10
lines changed

Orange/widgets/visualize/owscatterplotgraph.py

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
from collections import Counter
1+
from collections import Counter, defaultdict
22
import sys
33
import itertools
44
from xml.sax.saxutils import escape
5-
from math import log10, floor, ceil
5+
from math import log2, log10, floor, ceil
66

77
import numpy as np
88
from scipy.stats import linregress
99

1010
from AnyQt.QtCore import Qt, QObject, QEvent, QRectF, QPointF, QSize
1111
from AnyQt.QtGui import (
12-
QStaticText, QColor, QPen, QBrush, QPainterPath, QTransform, QPainter, QKeySequence)
12+
QStaticText, QColor, QPen, QBrush, QPainterPath, QTransform, QPainter, QKeySequence, QConicalGradient)
1313
from AnyQt.QtWidgets import QApplication, QToolTip, QPinchGesture, \
1414
QGraphicsTextItem, QGraphicsRectItem, QAction
1515

@@ -691,13 +691,13 @@ def update_data(self, attr_x, attr_y, reset_view=True):
691691
self.shown_x.name, self.shown_y.name)
692692
return
693693

694-
x_data, y_data = self.get_xy_data_positions(
694+
self.x_data, self.y_data = self.get_xy_data_positions(
695695
attr_x, attr_y, self.valid_data)
696-
self.n_points = len(x_data)
696+
self.n_points = len(self.x_data)
697697

698698
if reset_view:
699-
min_x, max_x = np.nanmin(x_data), np.nanmax(x_data)
700-
min_y, max_y = np.nanmin(y_data), np.nanmax(y_data)
699+
min_x, max_x = np.nanmin(self.x_data), np.nanmax(self.x_data)
700+
min_y, max_y = np.nanmin(self.y_data), np.nanmax(self.y_data)
701701
self.view_box.setRange(
702702
QRectF(min_x, min_y, max_x - min_x, max_y - min_y),
703703
padding=0.025)
@@ -712,6 +712,14 @@ def update_data(self, attr_x, attr_y, reset_view=True):
712712
else:
713713
self.set_labels(axis, None)
714714

715+
# compute overlaps of points for use in compute_colors and compute_sizes
716+
self.overlaps = []
717+
points = defaultdict(list)
718+
for i, xy in enumerate(zip(self.x_data, self.y_data)):
719+
points[xy].append(i)
720+
self.overlaps = [len(points[xy]) for i, xy in enumerate(zip(self.x_data, self.y_data))]
721+
self.overlap_factor = [1+log2(o) for o in self.overlaps]
722+
715723
color_data, brush_data = self.compute_colors()
716724
color_data_sel, brush_data_sel = self.compute_colors_sel()
717725
size_data = self.compute_sizes()
@@ -721,7 +729,7 @@ def update_data(self, attr_x, attr_y, reset_view=True):
721729
rgb_data = [pen.color().getRgb()[:3] for pen in color_data]
722730
self.density_img = classdensity.class_density_image(
723731
min_x, max_x, min_y, max_y, self.resolution,
724-
x_data, y_data, rgb_data)
732+
self.x_data, self.y_data, rgb_data)
725733
self.plot_widget.addItem(self.density_img)
726734

727735
self.data_indices = np.flatnonzero(self.valid_data)
@@ -730,11 +738,11 @@ def update_data(self, attr_x, attr_y, reset_view=True):
730738
self.shown_x.name, self.shown_y.name)
731739

732740
self.scatterplot_item = ScatterPlotItem(
733-
x=x_data, y=y_data, data=self.data_indices,
741+
x=self.x_data, y=self.y_data, data=self.data_indices,
734742
symbol=shape_data, size=size_data, pen=color_data, brush=brush_data
735743
)
736744
self.scatterplot_item_sel = ScatterPlotItem(
737-
x=x_data, y=y_data, data=self.data_indices,
745+
x=self.x_data, y=self.y_data, data=self.data_indices,
738746
symbol=shape_data, size=size_data + SELECTION_WIDTH,
739747
pen=color_data_sel, brush=brush_data_sel
740748
)
@@ -815,6 +823,10 @@ def compute_sizes(self):
815823
if np.any(nans):
816824
size_data[nans] = self.MinShapeSize - 2
817825
self.master.Information.missing_size(self.attr_size)
826+
827+
# scale sizes because of overlaps
828+
size_data = np.multiply(size_data, self.overlap_factor)
829+
818830
return size_data
819831

820832
def update_sizes(self):
@@ -957,6 +969,15 @@ def compute_colors(self, keep_colors=False):
957969
QBrush(QColor(col[0], col[1], col[2], alpha))]
958970
for col in colors])
959971
self.brush_colors = self.brush_colors[c_data]
972+
973+
# gray out overlapping points
974+
for i, xy in enumerate(zip(self.x_data, self.y_data)):
975+
if self.overlaps[i] > 1:
976+
self.brush_colors[i] = [
977+
QBrush(QColor(0, 0, 0, 0)),
978+
QBrush(QColor(128, 128, 128, alpha))]
979+
self.pen_colors[i] = _make_pen(QColor(128, 128, 128).darker(self.DarkerValue), 1.5)
980+
960981
if subset is not None:
961982
brush = np.where(
962983
subset,

0 commit comments

Comments
 (0)