Skip to content

Commit

Permalink
OWMosaic: Wrap legend
Browse files Browse the repository at this point in the history
  • Loading branch information
janezd committed Jun 7, 2019
1 parent 69f08be commit 1098e8d
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 38 deletions.
64 changes: 29 additions & 35 deletions Orange/widgets/visualize/owmosaic.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import defaultdict
from functools import reduce
from itertools import product, chain
from itertools import product, chain, repeat
from math import sqrt, log
from operator import mul, attrgetter

Expand All @@ -9,7 +9,8 @@
from scipy.special import comb
from AnyQt.QtCore import Qt, QSize, pyqtSignal as Signal
from AnyQt.QtGui import QColor, QPainter, QPen, QStandardItem
from AnyQt.QtWidgets import QGraphicsScene, QGraphicsLineItem
from AnyQt.QtWidgets import (
QGraphicsScene, QGraphicsLineItem, QGraphicsItemGroup)

from Orange.data import Table, filter, Variable, Domain
from Orange.data.sql.table import SqlTable, LARGE_TABLE, DEFAULT_SAMPLE_TIME
Expand All @@ -28,6 +29,7 @@
from Orange.widgets.utils.widgetpreview import WidgetPreview
from Orange.widgets.visualize.utils import (
CanvasText, CanvasRectangle, ViewWithPress, VizRankDialog)
from Orange.widgets.visualize.utils.plotutils import wrap_legend_items
from Orange.widgets.widget import OWWidget, Msg, Input, Output


Expand Down Expand Up @@ -813,42 +815,29 @@ def line(x1, y1, x2, y2):
"{}<hr>Instances: {}<br><br>{}".format(
condition, n_actual, text[:-4]))

def draw_legend(x0_x1, y0_y1):
x0, x1 = x0_x1
_, y1 = y0_y1
def create_legend():
if self.variable_color is None:
names = ["<-8", "-8:-4", "-4:-2", "-2:2", "2:4", "4:8", ">8",
"Residuals:"]
colors = self.RED_COLORS[::-1] + self.BLUE_COLORS[1:]
edges = repeat(Qt.black)
else:
names = get_variable_values_sorted(class_var) + \
[class_var.name + ":"]
colors = [QColor(*col) for col in class_var.colors]

names = [CanvasText(self.canvas, name, alignment=Qt.AlignVCenter)
for name in names]
totalwidth = sum(text.boundingRect().width() for text in names)

# compute the x position of the center of the legend
y = y1 + self.ATTR_NAME_OFFSET + self.ATTR_VAL_OFFSET + 35
distance = 30
startx = (x0 + x1) / 2 - (totalwidth + (len(names)) * distance) / 2

names[-1].setPos(startx + 15, y)
names[-1].show()
xoffset = names[-1].boundingRect().width() + distance
names = get_variable_values_sorted(class_var)
edges = colors = [QColor(*col) for col in class_var.colors]

items = []
size = 8
for i in range(len(names) - 1):
if self.variable_color is None:
edgecolor = Qt.black
else:
edgecolor = colors[i]

CanvasRectangle(self.canvas, startx + xoffset, y - size / 2,
size, size, edgecolor, colors[i])
names[i].setPos(startx + xoffset + 10, y)
xoffset += distance + names[i].boundingRect().width()
for name, color, edgecolor in zip(names, colors, edges):
item = QGraphicsItemGroup()
item.addToGroup(
CanvasRectangle(None, -size / 2, -size / 2, size, size,
edgecolor, color))
item.addToGroup(
CanvasText(None, name, size, 0, Qt.AlignVCenter))
items.append(item)
return wrap_legend_items(
items, hspacing=20, vspacing=16 + size,
max_width=self.canvas_view.width() - 2 * xoff)

self.canvas.clear()
self.areas = []
Expand Down Expand Up @@ -896,8 +885,10 @@ def get_max_label_width(attr):
maxw = max(int(t.boundingRect().width()), maxw)
return maxw

# get the maximum width of rectangle
xoff = 20
legend = create_legend()

# get the maximum width of rectangle
width = 20
max_ylabel_w1 = max_ylabel_w2 = 0
if len(attr_list) > 1:
Expand All @@ -913,10 +904,11 @@ def get_max_label_width(attr):
self.ATTR_VAL_OFFSET + max_ylabel_w2 - 10

# get the maximum height of rectangle
height = 100
yoff = 45
legendoff = yoff + self.ATTR_NAME_OFFSET + self.ATTR_VAL_OFFSET + 35
square_size = min(self.canvas_view.width() - width - 20,
self.canvas_view.height() - height - 20)
self.canvas_view.height() - legendoff
- legend.boundingRect().height())

if square_size < 0:
return # canvas is too small to draw rectangles
Expand All @@ -937,7 +929,9 @@ def get_max_label_width(attr):
draw_data(
attr_list, (xoff, xoff + square_size), (yoff, yoff + square_size),
0, "", len(attr_list), [], [])
draw_legend((xoff, xoff + square_size), (yoff, yoff + square_size))

self.canvas.addItem(legend)
legend.setPos(xoff, legendoff + square_size)
self.update_selection_rects()

@classmethod
Expand Down
3 changes: 2 additions & 1 deletion Orange/widgets/visualize/tests/test_owmosaic.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ def assertCount(cb_color, cb_attr, areas):
assertCount(1, [0, 1, 1, 1], 0)

@patch('Orange.widgets.visualize.owmosaic.CanvasRectangle')
def test_different_number_of_attributes(self, canvas_rectangle):
@patch('Orange.widgets.visualize.owmosaic.QGraphicsItemGroup.addToGroup')
def test_different_number_of_attributes(self, _, canvas_rectangle):
domain = Domain([DiscreteVariable(c, values="01") for c in "abcd"])
data = Table.from_list(
domain,
Expand Down
43 changes: 41 additions & 2 deletions Orange/widgets/visualize/utils/plotutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
)
from AnyQt.QtGui import QTransform
from AnyQt.QtWidgets import (
QGraphicsLineItem, QGraphicsSceneMouseEvent, QPinchGesture
)
QGraphicsLineItem, QGraphicsSceneMouseEvent, QPinchGesture,
QGraphicsItemGroup)

import pyqtgraph as pg

Expand Down Expand Up @@ -348,3 +348,42 @@ def mouseDragEvent(self, ev, axis=None):
else:
self.moved.emit(self.item_id, pos.x(), pos.y())
self.graph.show_indicator(self.item_id)


def wrap_legend_items(items, max_width, hspacing, vspacing):
def line_width(line):
return sum(item.boundingRect().width() for item in line) \
+ hspacing * (len(line) - 1)

def create_line(line, yi, centered=False, fixed_width=None):
x = (max_width - line_width(line)) / 2 if centered else 0
for item in line:
item.setPos(x, yi * vspacing)
paragraph.addToGroup(item)
if fixed_width:
x += fixed_width
else:
x += item.boundingRect().width() + hspacing

paragraph = QGraphicsItemGroup()
if line_width(items) < max_width:
create_line(items, 0, centered=True)
return paragraph

max_item = max(item.boundingRect().width() + hspacing for item in items)
in_line = int(max_width // max_item)
if in_line < 2:
lines = [[]]
for i, item in enumerate(items):
lines[-1].append(item)
if line_width(lines[-1]) > max_width and len(lines[-1]) > 1:
lines.append([lines[-1].pop()])
fixed_width = None
else:
lines = [items[i:i + in_line]
for i in range(0, len(items) + in_line - 1, in_line)]
fixed_width = max_item

for yi, line in enumerate(lines):
create_line(line, yi, fixed_width=fixed_width)
return paragraph

0 comments on commit 1098e8d

Please sign in to comment.