Skip to content

Commit 1c84566

Browse files
authored
Merge pull request #4365 from ales-erjavec/graphics-text-list
[FIX] Fix slow clear/delete in 'Heat Map' 'Hier. Clustering', 'Distance Map'
2 parents 8cd240f + c5c2609 commit 1c84566

6 files changed

Lines changed: 415 additions & 376 deletions

File tree

Orange/widgets/unsupervised/owdistancemap.py

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
import numpy
66

77
from AnyQt.QtWidgets import (
8-
QFormLayout, QGraphicsRectItem, QGraphicsGridLayout, QApplication
8+
QFormLayout, QGraphicsRectItem, QGraphicsGridLayout, QApplication,
9+
QSizePolicy
910
)
1011
from AnyQt.QtGui import (
1112
QFontMetrics, QPen, QIcon, QPixmap, QLinearGradient, QPainter, QColor,
12-
QBrush, QTransform
13+
QBrush, QTransform, QFont
1314
)
1415
from AnyQt.QtCore import Qt, QRect, QRectF, QSize, QPointF
1516
from AnyQt.QtCore import pyqtSignal as Signal
@@ -25,10 +26,12 @@
2526
from Orange.widgets.utils import itemmodels, colorbrewer
2627
from Orange.widgets.utils.annotated_data import (create_annotated_table,
2728
ANNOTATED_DATA_SIGNAL_NAME)
29+
from Orange.widgets.utils.graphicstextlist import TextListWidget
2830
from Orange.widgets.utils.widgetpreview import WidgetPreview
2931
from Orange.widgets.widget import Input, Output
3032
from Orange.widgets.unsupervised.owhierarchicalclustering import (
31-
DendrogramWidget, GraphicsSimpleTextList)
33+
DendrogramWidget
34+
)
3235

3336
def _remove_item(item):
3437
item.setParentItem(None)
@@ -379,10 +382,14 @@ def __init__(self):
379382
self.grid.addItem(self.top_dendrogram, 0, 1)
380383

381384
self.right_labels = TextList(
382-
alignment=Qt.AlignLeft)
383-
385+
alignment=Qt.AlignLeft | Qt.AlignVCenter,
386+
sizePolicy=QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
387+
)
384388
self.bottom_labels = TextList(
385-
orientation=Qt.Horizontal, alignment=Qt.AlignRight)
389+
orientation=Qt.Horizontal,
390+
alignment=Qt.AlignRight | Qt.AlignVCenter,
391+
sizePolicy=QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
392+
)
386393

387394
self.grid.addItem(self.right_labels, 1, 2)
388395
self.grid.addItem(self.bottom_labels, 2, 1)
@@ -606,7 +613,7 @@ def _set_labels(self, labels):
606613
labels = [labels[i] for i in sortind]
607614

608615
for textlist in [self.right_labels, self.bottom_labels]:
609-
textlist.set_labels(labels or [])
616+
textlist.setItems(labels or [])
610617
textlist.setVisible(bool(labels))
611618

612619
constraint = -1 if labels else 0
@@ -678,18 +685,18 @@ def send_report(self):
678685
self.report_plot()
679686

680687

681-
class TextList(GraphicsSimpleTextList):
688+
class TextList(TextListWidget):
682689
def resizeEvent(self, event):
683690
super().resizeEvent(event)
684691
self._updateFontSize()
685692

686693
def _updateFontSize(self):
687694
crect = self.contentsRect()
688-
if self.orientation == Qt.Vertical:
695+
if self.orientation() == Qt.Vertical:
689696
h = crect.height()
690697
else:
691698
h = crect.width()
692-
n = len(getattr(self, "label_items", []))
699+
n = self.count()
693700
if n == 0:
694701
return
695702

@@ -698,15 +705,12 @@ def _updateFontSize(self):
698705
else:
699706
maxfontsize = QApplication.instance().font().pointSize()
700707

701-
lineheight = max(1, h / n)
708+
lineheight = max(1., h / n)
702709
fontsize = min(self._point_size(lineheight), maxfontsize)
703710

704-
font = self.font()
705-
font.setPointSize(fontsize)
706-
707-
self.setFont(font)
708-
self.layout().invalidate()
709-
self.layout().activate()
711+
font_ = QFont()
712+
font_.setPointSize(fontsize)
713+
self.setFont(font_)
710714

711715
def _point_size(self, height):
712716
font = self.font()
@@ -717,7 +721,6 @@ def _point_size(self, height):
717721
font.setPointSize(height - fix)
718722
return height - fix
719723

720-
721724
##########################
722725
# Color palette management
723726
##########################

Orange/widgets/unsupervised/owhierarchicalclustering.py

Lines changed: 7 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import numpy as np
1111

1212
from AnyQt.QtWidgets import (
13-
QGraphicsWidget, QGraphicsObject, QGraphicsLinearLayout, QGraphicsPathItem,
13+
QGraphicsWidget, QGraphicsObject, QGraphicsPathItem,
1414
QGraphicsScene, QGridLayout, QSizePolicy,
1515
QGraphicsSimpleTextItem, QGraphicsLayoutItem, QAction, QComboBox,
1616
QGraphicsItemGroup, QGraphicsGridLayout, QGraphicsSceneMouseEvent
@@ -41,6 +41,7 @@
4141
from Orange.widgets.widget import Input, Output, Msg
4242

4343
from Orange.widgets.utils.stickygraphicsview import StickyGraphicsView
44+
from Orange.widgets.utils.graphicstextlist import TextListWidget
4445

4546
__all__ = ["OWHierarchicalClustering"]
4647

@@ -287,6 +288,8 @@ def __init__(self, parent=None, root=None, orientation=Left,
287288
**kwargs):
288289

289290
super().__init__(None, **kwargs)
291+
# Filter all events from children (`ClusterGraphicsItem`s)
292+
self.setFiltersChildEvents(True)
290293
self.orientation = orientation
291294
self._root = None
292295
#: A tree with dendrogram geometry
@@ -311,12 +314,6 @@ def __init__(self, parent=None, root=None, orientation=Left,
311314
self.setParentItem(parent)
312315

313316
def clear(self):
314-
# Remove event filter from all items before removal.
315-
# Each removeItem is linear in number of installed filters in the whole
316-
# scene -> so this would be quadratic for us (not accounting any other
317-
# filters not part of DendrogramWidget).
318-
for item in self._items.values():
319-
item.removeSceneEventFilter(self)
320317
scene = self.scene()
321318
if scene is not None:
322319
scene.removeItem(self._itemgroup)
@@ -354,7 +351,6 @@ def set_root(self, root):
354351
item.setAcceptHoverEvents(True)
355352
item.setPen(pen)
356353
item.node = node
357-
item.installSceneEventFilter(self)
358354
for branch in node.branches:
359355
assert branch in self._items
360356
self._cluster_parent[branch] = node
@@ -1062,11 +1058,10 @@ def axis_view(orientation):
10621058
self.dendrogram.selectionChanged.connect(self._invalidate_output)
10631059
self.dendrogram.selectionEdited.connect(self._selection_edited)
10641060

1065-
self.labels = GraphicsSimpleTextList()
1061+
self.labels = TextListWidget()
10661062
self.labels.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred)
10671063
self.labels.setAlignment(Qt.AlignLeft)
10681064
self.labels.setMaximumWidth(200)
1069-
self.labels.layout().setSpacing(0)
10701065

10711066
scenelayout.addItem(self.top_axis, 0, 0,
10721067
alignment=Qt.AlignLeft | Qt.AlignVCenter)
@@ -1156,8 +1151,8 @@ def _set_items(self, items, axis=1):
11561151
else self.annotation_if_enumerate
11571152

11581153
def _clear_plot(self):
1159-
self.labels.set_labels([])
11601154
self.dendrogram.set_root(None)
1155+
self.labels.setItems([])
11611156

11621157
def _set_displayed_root(self, root):
11631158
self._clear_plot()
@@ -1223,7 +1218,7 @@ def _update_labels(self):
12231218
labels = [", ".join(labels[leaf.value.first: leaf.value.last])
12241219
for leaf in joined]
12251220

1226-
self.labels.set_labels(labels)
1221+
self.labels.setItems(labels)
12271222
self.labels.setMinimumWidth(1 if labels else -1)
12281223

12291224
def _restore_selection(self, state):
@@ -1614,83 +1609,6 @@ def qfont_scaled(font, factor):
16141609
return scaled
16151610

16161611

1617-
class GraphicsSimpleTextList(QGraphicsWidget):
1618-
"""A simple text list widget."""
1619-
1620-
def __init__(self, labels=[], orientation=Qt.Vertical,
1621-
alignment=Qt.AlignCenter, parent=None):
1622-
QGraphicsWidget.__init__(self, parent)
1623-
layout = QGraphicsLinearLayout(orientation)
1624-
layout.setContentsMargins(0, 0, 0, 0)
1625-
layout.setSpacing(0)
1626-
self.setLayout(layout)
1627-
self.orientation = orientation
1628-
self.alignment = alignment
1629-
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
1630-
self.label_items = []
1631-
self.set_labels(labels)
1632-
1633-
def clear(self):
1634-
"""Remove all text items."""
1635-
layout = self.layout()
1636-
for i in reversed(range(layout.count())):
1637-
witem = layout.itemAt(i)
1638-
witem.item.setParentItem(None)
1639-
if self.scene():
1640-
self.scene().removeItem(witem.item)
1641-
layout.removeAt(i)
1642-
1643-
self.label_items = []
1644-
self.updateGeometry()
1645-
1646-
def set_labels(self, labels):
1647-
"""Set the text labels."""
1648-
self.clear()
1649-
orientation = Qt.Horizontal if self.orientation == Qt.Vertical else Qt.Vertical
1650-
for text in labels:
1651-
item = QGraphicsSimpleTextItem(text, self)
1652-
item.setFont(self.font())
1653-
item.setToolTip(text)
1654-
witem = WrapperLayoutItem(item, orientation, parent=self)
1655-
self.layout().addItem(witem)
1656-
self.layout().setAlignment(witem, self.alignment)
1657-
self.label_items.append(item)
1658-
1659-
self.layout().activate()
1660-
self.updateGeometry()
1661-
1662-
def setAlignment(self, alignment):
1663-
"""Set alignment of text items in the widget
1664-
"""
1665-
self.alignment = alignment
1666-
layout = self.layout()
1667-
for i in range(layout.count()):
1668-
layout.setAlignment(layout.itemAt(i), alignment)
1669-
1670-
def setVisible(self, visible):
1671-
QGraphicsWidget.setVisible(self, visible)
1672-
self.updateGeometry()
1673-
1674-
def changeEvent(self, event):
1675-
if event.type() == QEvent.FontChange:
1676-
self.__update_font()
1677-
return super().changeEvent(event)
1678-
1679-
def __iter__(self):
1680-
return iter(self.label_items)
1681-
1682-
def __update_font(self):
1683-
for item in self.label_items:
1684-
item.setFont(self.font())
1685-
1686-
layout = self.layout()
1687-
for i in range(layout.count()):
1688-
layout.itemAt(i).updateGeometry()
1689-
1690-
self.layout().invalidate()
1691-
self.updateGeometry()
1692-
1693-
16941612
class WrapperLayoutItem(QGraphicsLayoutItem):
16951613
"""A Graphics layout item wrapping a QGraphicsItem allowing it
16961614
to be managed by a layout.

0 commit comments

Comments
 (0)