11from collections import defaultdict
22from functools import reduce
3- from itertools import product , chain
3+ from itertools import product , chain , repeat
44from math import sqrt , log
55from operator import mul , attrgetter
66
99from scipy .special import comb
1010from AnyQt .QtCore import Qt , QSize , pyqtSignal as Signal
1111from AnyQt .QtGui import QColor , QPainter , QPen , QStandardItem
12- from AnyQt .QtWidgets import QGraphicsScene , QGraphicsLineItem
12+ from AnyQt .QtWidgets import (
13+ QGraphicsScene , QGraphicsLineItem , QGraphicsItemGroup )
1314
1415from Orange .data import Table , filter , Variable , Domain
1516from Orange .data .sql .table import SqlTable , LARGE_TABLE , DEFAULT_SAMPLE_TIME
2829from Orange .widgets .utils .widgetpreview import WidgetPreview
2930from Orange .widgets .visualize .utils import (
3031 CanvasText , CanvasRectangle , ViewWithPress , VizRankDialog )
32+ from Orange .widgets .visualize .utils .plotutils import wrap_legend_items
3133from Orange .widgets .widget import OWWidget , Msg , Input , Output
3234
3335
@@ -813,42 +815,29 @@ def line(x1, y1, x2, y2):
813815 "{}<hr>Instances: {}<br><br>{}" .format (
814816 condition , n_actual , text [:- 4 ]))
815817
816- def draw_legend (x0_x1 , y0_y1 ):
817- x0 , x1 = x0_x1
818- _ , y1 = y0_y1
818+ def create_legend ():
819819 if self .variable_color is None :
820820 names = ["<-8" , "-8:-4" , "-4:-2" , "-2:2" , "2:4" , "4:8" , ">8" ,
821821 "Residuals:" ]
822822 colors = self .RED_COLORS [::- 1 ] + self .BLUE_COLORS [1 :]
823+ edges = repeat (Qt .black )
823824 else :
824- names = get_variable_values_sorted (class_var ) + \
825- [class_var .name + ":" ]
826- colors = [QColor (* col ) for col in class_var .colors ]
827-
828- names = [CanvasText (self .canvas , name , alignment = Qt .AlignVCenter )
829- for name in names ]
830- totalwidth = sum (text .boundingRect ().width () for text in names )
831-
832- # compute the x position of the center of the legend
833- y = y1 + self .ATTR_NAME_OFFSET + self .ATTR_VAL_OFFSET + 35
834- distance = 30
835- startx = (x0 + x1 ) / 2 - (totalwidth + (len (names )) * distance ) / 2
836-
837- names [- 1 ].setPos (startx + 15 , y )
838- names [- 1 ].show ()
839- xoffset = names [- 1 ].boundingRect ().width () + distance
825+ names = get_variable_values_sorted (class_var )
826+ edges = colors = [QColor (* col ) for col in class_var .colors ]
840827
828+ items = []
841829 size = 8
842- for i in range (len (names ) - 1 ):
843- if self .variable_color is None :
844- edgecolor = Qt .black
845- else :
846- edgecolor = colors [i ]
847-
848- CanvasRectangle (self .canvas , startx + xoffset , y - size / 2 ,
849- size , size , edgecolor , colors [i ])
850- names [i ].setPos (startx + xoffset + 10 , y )
851- xoffset += distance + names [i ].boundingRect ().width ()
830+ for name , color , edgecolor in zip (names , colors , edges ):
831+ item = QGraphicsItemGroup ()
832+ item .addToGroup (
833+ CanvasRectangle (None , - size / 2 , - size / 2 , size , size ,
834+ edgecolor , color ))
835+ item .addToGroup (
836+ CanvasText (None , name , size , 0 , Qt .AlignVCenter ))
837+ items .append (item )
838+ return wrap_legend_items (
839+ items , hspacing = 20 , vspacing = 16 + size ,
840+ max_width = self .canvas_view .width () - 2 * xoff )
852841
853842 self .canvas .clear ()
854843 self .areas = []
@@ -896,8 +885,10 @@ def get_max_label_width(attr):
896885 maxw = max (int (t .boundingRect ().width ()), maxw )
897886 return maxw
898887
899- # get the maximum width of rectangle
900888 xoff = 20
889+ legend = create_legend ()
890+
891+ # get the maximum width of rectangle
901892 width = 20
902893 max_ylabel_w1 = max_ylabel_w2 = 0
903894 if len (attr_list ) > 1 :
@@ -913,10 +904,11 @@ def get_max_label_width(attr):
913904 self .ATTR_VAL_OFFSET + max_ylabel_w2 - 10
914905
915906 # get the maximum height of rectangle
916- height = 100
917907 yoff = 45
908+ legendoff = yoff + self .ATTR_NAME_OFFSET + self .ATTR_VAL_OFFSET + 35
918909 square_size = min (self .canvas_view .width () - width - 20 ,
919- self .canvas_view .height () - height - 20 )
910+ self .canvas_view .height () - legendoff
911+ - legend .boundingRect ().height ())
920912
921913 if square_size < 0 :
922914 return # canvas is too small to draw rectangles
@@ -937,7 +929,12 @@ def get_max_label_width(attr):
937929 draw_data (
938930 attr_list , (xoff , xoff + square_size ), (yoff , yoff + square_size ),
939931 0 , "" , len (attr_list ), [], [])
940- draw_legend ((xoff , xoff + square_size ), (yoff , yoff + square_size ))
932+
933+ self .canvas .addItem (legend )
934+ legend .setPos (
935+ xoff - legend .boundingRect ().x ()
936+ + max (0 , (square_size - legend .boundingRect ().width ()) / 2 ),
937+ legendoff + square_size )
941938 self .update_selection_rects ()
942939
943940 @classmethod
0 commit comments