def draw_attribute(self, y, atr_name, atr_val, atr_contrib, error): fix = (self.offset_left + self.atr_area_w) """vertical line where x = 0""" self.scene.addLine(0 + fix, y, 0 + fix, y + self.rect_height, self.black_pen) """borders""" self.scene.addLine(self.offset_left, y, fix + self.atr_area_w, y, self.gray_pen) self.scene.addLine(self.offset_left, y + self.rect_height, fix + self.atr_area_w, y + self.rect_height, self.gray_pen) if atr_name is not None and atr_val is not None and atr_contrib is not None: atr_contrib_x = atr_contrib * self.scale + fix error_x = error * self.scale padded_rect = self.rect_height - 2 * self.offset_y len_rec = 2 * error_x graphed_rect = QGraphicsRectItem( atr_contrib_x - error_x, y + self.offset_y, len_rec, padded_rect) graphed_rect.setBrush(self.brush) graphed_rect.setPen(QPen(Qt.NoPen)) self.scene.addItem(graphed_rect) """vertical line marks calculated contribution of attribute""" self.atr_line = self.scene.addLine(atr_contrib_x, y + self.offset_y + 2, atr_contrib_x, y + self.rect_height - self.offset_y - 2, self.blue_pen) """atr name and value on the left""" self.place_left(QGraphicsSimpleTextItem( atr_val, None), y + self.rect_height/2) self.place_left_edge(QGraphicsSimpleTextItem( atr_name, None), y + self.rect_height/2) """atr score on the right""" self.place_right(self.format_marking( atr_contrib), y + self.rect_height/2)
def __init__(self, value: float, label: Tuple[str, float], norm_value: float): super().__init__() color = QColor(*self.light_rgb) self.value = value self.norm_value = norm_value self.setPath(self.get_path()) pen = QPen(color) pen.setWidth(2) self.setPen(pen) value = np.abs(value) self.value_item = item = QGraphicsSimpleTextItem(_str(value)) item.setToolTip(_str(value, 3)) font = item.font() font.setPixelSize(11) item.setFont(font) width = item.boundingRect().width() item.setX(StripeItem.WIDTH / 2 - width / 2) item.setPen(color) item.setBrush(color) self.label_item = QGraphicsSimpleTextItem( f"{label[0]} = {_str(label[1])}") self.label_item.setToolTip(f"{label[0]} = {_str(label[1], 3)}") self.label_item.setX(StripeItem.WIDTH + StripePlot.SPACING)
class _SelectionItem(QGraphicsItemGroup): def __init__(self, parent, path, unscaled_path, label=""): super().__init__(parent) self.path = QGraphicsPathItem(path, self) self.path.setPen(make_pen(width=1, cosmetic=True)) self.addToGroup(self.path) self.label = QGraphicsSimpleTextItem(label) self._update_label_pos() self.addToGroup(self.label) self.unscaled_path = unscaled_path def set_path(self, path): self.path.setPath(path) self._update_label_pos() def set_label(self, label): self.label.setText(label) self._update_label_pos() def set_color(self, color): self.path.setBrush(QColor(color)) def _update_label_pos(self): path = self.path.path() elements = (path.elementAt(i) for i in range(path.elementCount())) points = ((p.x, p.y) for p in elements) p1, p2, *rest = sorted(points) x, y = p1[0], (p1[1] + p2[1]) / 2 brect = self.label.boundingRect() # leaf nodes' paths are 4 pixels higher; leafs are `len(rest) == 3` self.label.setPos(x - brect.width() - 4, y - brect.height() + 4 * (len(rest) == 3))
def __setup(self): # Setup the subwidgets/groups/layout smax = max((np.nanmax(g.scores) for g in self.__groups if g.scores.size), default=1) smax = 1 if np.isnan(smax) else smax smin = min((np.nanmin(g.scores) for g in self.__groups if g.scores.size), default=-1) smin = -1 if np.isnan(smin) else smin smin = min(smin, 0) font = self.font() font.setPixelSize(self.__barHeight) axispen = QPen(Qt.black) ax = pg.AxisItem(parent=self, orientation="top", maxTickLength=7, pen=axispen) ax.setRange(smin, smax) self.__topScale = ax self.layout().addItem(ax, 0, 2) for i, group in enumerate(self.__groups): silhouettegroup = BarPlotItem(parent=self) silhouettegroup.setBrush(QBrush(QColor(*group.color))) silhouettegroup.setPen(self.__pen) silhouettegroup.setDataRange(smin, smax) silhouettegroup.setPlotData(group.scores) silhouettegroup.setPreferredBarSize(self.__barHeight) silhouettegroup.setData(0, group.indices) self.layout().addItem(silhouettegroup, i + 1, 2) if group.label: self.layout().addItem(Line(orientation=Qt.Vertical), i + 1, 1) label = QGraphicsSimpleTextItem(self) label.setText("{} ({})".format(escape(group.label), len(group.scores))) item = WrapperLayoutItem(label, Qt.Vertical, parent=self) self.layout().addItem(item, i + 1, 0, Qt.AlignCenter) textlist = TextListWidget(self, font=font) sp = textlist.sizePolicy() sp.setVerticalPolicy(QSizePolicy.Ignored) textlist.setSizePolicy(sp) textlist.setParent(self) if group.rownames is not None: textlist.setItems(group.items) textlist.setVisible(self.__rowNamesVisible) else: textlist.setVisible(False) self.layout().addItem(textlist, i + 1, 3) ax = pg.AxisItem(parent=self, orientation="bottom", maxTickLength=7, pen=axispen) ax.setRange(smin, smax) self.__bottomScale = ax self.layout().addItem(ax, len(self.__groups) + 1, 2)
def __setup(self): # Setup the subwidgets/groups/layout smax = max((numpy.max(g.scores) for g in self.__groups if g.scores.size), default=1) smin = min((numpy.min(g.scores) for g in self.__groups if g.scores.size), default=-1) smin = min(smin, 0) font = self.font() font.setPixelSize(self.__barHeight) axispen = QPen(Qt.black) ax = pg.AxisItem(parent=self, orientation="top", maxTickLength=7, pen=axispen) ax.setRange(smin, smax) self.layout().addItem(ax, 0, 2) for i, group in enumerate(self.__groups): silhouettegroup = BarPlotItem(parent=self) silhouettegroup.setBrush(self.__brush) silhouettegroup.setPen(self.__pen) silhouettegroup.setDataRange(smin, smax) silhouettegroup.setPlotData(group.scores) silhouettegroup.setPreferredBarSize(self.__barHeight) silhouettegroup.setData(0, group.indices) self.layout().addItem(silhouettegroup, i + 1, 2) if group.label: line = QFrame(frameShape=QFrame.VLine) proxy = QGraphicsProxyWidget(self) proxy.setWidget(line) self.layout().addItem(proxy, i + 1, 1) label = QGraphicsSimpleTextItem(self) label.setText("{} ({})".format(escape(group.label), len(group.scores))) item = WrapperLayoutItem(label, Qt.Vertical, parent=self) self.layout().addItem(item, i + 1, 0, Qt.AlignCenter) textlist = TextListWidget(self, font=font) sp = textlist.sizePolicy() sp.setVerticalPolicy(QSizePolicy.Ignored) textlist.setSizePolicy(sp) textlist.setParent(self) if group.rownames is not None: textlist.setItems(group.items) textlist.setVisible(self.__rowNamesVisible) else: textlist.setVisible(False) self.layout().addItem(textlist, i + 1, 3) ax = pg.AxisItem(parent=self, orientation="bottom", maxTickLength=7, pen=axispen) ax.setRange(smin, smax) self.layout().addItem(ax, len(self.__groups) + 1, 2)
def draw_axis(self): """Draw the horizontal axis and sets self.scale_x""" misssing_stats = not self.stats stats = self.stats or [BoxData(np.array([[0.], [1.]]), self.attribute)] mean_labels = self.mean_labels or [ self.mean_label(stats[0], self.attribute, "") ] bottom = min(stat.a_min for stat in stats) top = max(stat.a_max for stat in stats) first_val, step = compute_scale(bottom, top) while bottom <= first_val: first_val -= step bottom = first_val no_ticks = math.ceil((top - first_val) / step) + 1 top = max(top, first_val + no_ticks * step) gbottom = min(bottom, min(stat.mean - stat.dev for stat in stats)) gtop = max(top, max(stat.mean + stat.dev for stat in stats)) bv = self.box_view viewrect = bv.viewport().rect().adjusted(15, 15, -15, -30) self.scale_x = scale_x = viewrect.width() / (gtop - gbottom) # In principle we should repeat this until convergence since the new # scaling is too conservative. (No chance am I doing this.) mlb = min(stat.mean + mean_lab.min_x / scale_x for stat, mean_lab in zip(stats, mean_labels)) if mlb < gbottom: gbottom = mlb self.scale_x = scale_x = viewrect.width() / (gtop - gbottom) self.scene_min_x = gbottom * scale_x self.scene_max_x = gtop * scale_x self.scene_width = self.scene_max_x - self.scene_min_x val = first_val last_text = self.scene_min_x while True: l = self.box_scene.addLine(val * scale_x, -1, val * scale_x, 1, self._pen_axis_tick) l.setZValue(100) t = QGraphicsSimpleTextItem( self.attribute.str_val(val) if not misssing_stats else "?") t.setFont(self._axis_font) t.setFlags(t.flags() | QGraphicsItem.ItemIgnoresTransformations) r = t.boundingRect() x_start = val * scale_x - r.width() / 2 x_finish = x_start + r.width() if x_start > last_text + 10 and x_finish < self.scene_max_x: t.setPos(x_start, 8) self.box_scene.addItem(t) last_text = x_finish if val >= top: break val += step self.box_scene.addLine(bottom * scale_x - 4, 0, top * scale_x + 4, 0, self._pen_axis)
def __init__(self, parent, label: str): self.__name: str = None self.__value: Optional[str] = None self.__name_item = QGraphicsSimpleTextItem() self.__value_item = QGraphicsSimpleTextItem() font = Updater.change_font(QFont(), self.VALUE_FONT_SETTING) self.__value_item.setFont(font) self.__max_len = self.MAX_LABEL_LEN super().__init__(parent) self._set_data(label)
def _set_labels(self, labels: List[str]): for i, (label, _) in enumerate(zip(labels, self.__violin_items)): short = f"{label[:self.MAX_ATTR_LEN - 1]}..." \ if len(label) > self.MAX_ATTR_LEN else label text = QGraphicsSimpleTextItem(short, self) text.setToolTip(label) item = SimpleLayoutItem(text) item.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.__layout.addItem(item, i, ViolinPlot.LABEL_COLUMN, Qt.AlignRight | Qt.AlignVCenter)
def __init__(self, name, values, scale, name_offset, offset, labels=None): super().__init__() # leading label font = name.document().defaultFont() if self.bold_label: font.setWeight(QFont.Bold) name.setFont(font) name.setPos(name_offset, -10) name.setParentItem(self) # prediction marker self.dot = self.DOT_ITEM_CLS(self.dot_r, scale, offset, values[0], values[-1]) self.dot.setParentItem(self) # line line = QGraphicsLineItem( min(values) * scale + offset, 0, max(values) * scale + offset, 0) line.setParentItem(self) if labels is None: labels = [str(abs(v) if v == -0 else v) for v in values] old_x_tick = None shown_items = [] w = QGraphicsSimpleTextItem(labels[0]).boundingRect().width() text_finish = values[0] * scale - w + offset - 10 for i, (label, value) in enumerate(zip(labels, values)): text = QGraphicsSimpleTextItem(label) x_text = value * scale - text.boundingRect().width() / 2 + offset if text_finish > x_text - 10: y_text, y_tick = self.dot_r * 0.7, 0 text_finish = values[0] * scale + offset else: y_text = -text.boundingRect().height() - self.dot_r * 0.7 y_tick = -self.tick_height text_finish = x_text + text.boundingRect().width() text.setPos(x_text, y_text) if not collides(text, shown_items): text.setParentItem(self) shown_items.append(text) x_tick = value * scale - self.tick_width / 2 + offset tick = QGraphicsRectItem(x_tick, y_tick, self.tick_width, self.tick_height) tick.setBrush(QColor(Qt.black)) tick.setParentItem(self) if self.half_tick_height and i: x = x_tick - (x_tick - old_x_tick) / 2 half_tick = QGraphicsLineItem(x, -self.half_tick_height, x, 0) half_tick.setParentItem(self) old_x_tick = x_tick
def display_changed_disc(self): self.clear_scene() self.attr_labels = [QGraphicsSimpleTextItem(lab) for lab in self.label_txts_all] if not self.stretched: if self.group_var: self.labels = [ QGraphicsTextItem("{}".format(int(sum(cont)))) for cont in self.conts] else: self.labels = [ QGraphicsTextItem(str(int(sum(self.dist))))] self.draw_axis_disc() if self.group_var: self.boxes = [self.strudel(cont, i) for i, cont in enumerate(self.conts)] else: self.boxes = [self.strudel(self.dist)] for row, box in enumerate(self.boxes): y = (-len(self.boxes) + row) * 40 + 10 label = self.attr_labels[row] b = label.boundingRect() label.setPos(-b.width() - 10, y - b.height() / 2) self.box_scene.addItem(label) if not self.stretched: label = self.labels[row] b = label.boundingRect() if self.group_var: right = self.scale_x * sum(self.conts[row]) else: right = self.scale_x * sum(self.dist) label.setPos(right + 10, y - b.height() / 2) self.box_scene.addItem(label) if self.attribute is not self.group_var: for text_item, bar_part in zip(box[1::2], box[::2]): label = QGraphicsSimpleTextItem( text_item.toPlainText()) label.setPos(bar_part.boundingRect().x(), y - label.boundingRect().height() - 8) self.box_scene.addItem(label) for item in box: if isinstance(item, QGraphicsTextItem): continue self.box_scene.addItem(item) item.setPos(0, y) self.box_scene.setSceneRect(-self.label_width - 5, -30 - len(self.boxes) * 40, self.scene_width, len(self.boxes * 40) + 90) self.infot1.setText("") self.select_box_items()
def draw_header_footer(self, wp, header_h, unit_pixels, last_y, first_y, marking_len=15): """header""" max_x = self.max_contrib * self.scale atr_label = QGraphicsSimpleTextItem("Name", None) val_label = QGraphicsSimpleTextItem("Value", None) score_label = QGraphicsSimpleTextItem("Score", None) font = score_label.font() font.setBold(True) font.setPointSize(13) atr_label.setFont(font) val_label.setFont(font) score_label.setFont(font) white_pen = QPen(Qt.white, 3) fix = self.offset_left + self.atr_area_w self.place_left(val_label, -self.atr_area_h - header_h*0.85) self.place_left_edge(atr_label, -self.atr_area_h - header_h*0.85) self.place_right(score_label, -self.atr_area_h - header_h*0.85) self.scene.addLine(-max_x + fix, -self.atr_area_h - header_h, max_x + fix, -self.atr_area_h - header_h, white_pen) """footer""" line_y = max(first_y + wp.height() + header_h/2 - 10, last_y + header_h/2 + self.rect_height) self.scene.addLine(-max_x + fix, line_y, max_x + fix, line_y, self.black_pen) previous = 0 recomended_d = 35 for i in range(0, int(self.max_contrib / self.unit) + 1): x = unit_pixels * i """grid lines""" self.scene.addLine(x + fix, first_y, x + fix, line_y, self.light_gray_pen) self.scene.addLine(-x + fix, first_y, -x + fix, line_y, self.light_gray_pen) self.scene.addLine(x + fix, line_y, x + fix, line_y + marking_len, self.black_pen) self.scene.addLine(-x + fix, line_y, -x + fix, line_y + marking_len, self.black_pen) """markings on the ruler""" if x + fix - previous > recomended_d: self.place_centered(self.format_marking( i*self.unit), x + fix, line_y + marking_len + 5) if x > 0: self.place_centered( self.format_marking(-i*self.unit), -x + fix, line_y + marking_len + 5) previous = x + fix
def __init__(self, parent, path, unscaled_path, label=""): super().__init__(parent) self.path = QGraphicsPathItem(path, self) self.path.setPen(make_pen(width=1, cosmetic=True)) self.addToGroup(self.path) self.label = QGraphicsSimpleTextItem(label) self._update_label_pos() self.addToGroup(self.label) self.unscaled_path = unscaled_path
def _add_low_label(self): font = self.font() font.setPixelSize(9) item = QGraphicsSimpleTextItem("Low") item.setFont(font) item.setX(self.BAR_WIDTH + self.__offset) item.setY(self.__bar_height - item.boundingRect().height()) self.__group.addToGroup(item)
def __setup(self) -> None: self.__clear() font = self.__effectiveFont if self.__autoScale else self.font() assert self.__group is None group = QGraphicsItemGroup() for text in self.__items: t = QGraphicsSimpleTextItem(group) t.setFont(font) t.setText(text) t.setToolTip(text) t.setData(0, text) self.__textitems.append(t) group.setParentItem(self) self.__group = group
def get_needed_offset(self, explanations): max_n = 0 word = "" max_v = 0 val = "" for e in explanations: if max_n < len(str(e._metas[0])): word = str(e._metas[0]) max_n = len(str(e._metas[0])) if max_v < len(str(e._metas[1])): val = str(e._metas[1]) max_v = len(str(e._metas[1])) w = QGraphicsSimpleTextItem(word, None) v = QGraphicsSimpleTextItem(val, None) return w.boundingRect().width(), v.boundingRect().width()
def _add_high_label(self): font = self.font() font.setPixelSize(9) item = QGraphicsSimpleTextItem("High") item.setFont(font) item.setX(self.BAR_WIDTH + self.__offset) item.setY(0) self.__group.addToGroup(item)
def layout_changed(self): attr = self.attribute if not attr: return self.clear_scene() if self.dataset is None or len(self.conts) == len(self.dist) == 0: return if not self.is_continuous: self.display_changed_disc() return self.mean_labels = [ self.mean_label(stat, attr, lab) for stat, lab in zip(self.stats, self.label_txts) ] self.draw_axis() self.boxes = [self.box_group(stat) for stat in self.stats] self.labels = [ self.label_group(stat, attr, mean_lab) for stat, mean_lab in zip(self.stats, self.mean_labels) ] self.attr_labels = [ QGraphicsSimpleTextItem(lab) for lab in self.label_txts ] for it in chain(self.labels, self.attr_labels): self.box_scene.addItem(it) self.display_changed()
def _display_changed_cont(self): self.mean_labels = [self.mean_label(stat, self.attribute, lab) for stat, lab in zip(self.stats, self.label_txts)] self.draw_axis() self.boxes = [self.box_group(stat) for stat in self.stats] self.labels = [self.label_group(stat, self.attribute, mean_lab) for stat, mean_lab in zip(self.stats, self.mean_labels)] self.attr_labels = [QGraphicsSimpleTextItem(lab) for lab in self.label_txts] for it in chain(self.labels, self.attr_labels): self.box_scene.addItem(it) self.order = list(range(len(self.stats))) criterion = self._sorting_criteria_attrs[self.compare] if criterion: vals = [getattr(stat, criterion) for stat in self.stats] overmax = max((val for val in vals if val is not None), default=0) \ + 1 vals = [val if val is not None else overmax for val in vals] self.order = sorted(self.order, key=vals.__getitem__) heights = 90 if self.show_annotations else 60 for row, box_index in enumerate(self.order): y = (-len(self.stats) + row) * heights + 10 for item in self.boxes[box_index]: self.box_scene.addItem(item) item.setY(y) labels = self.labels[box_index] if self.show_annotations: labels.show() labels.setY(y) else: labels.hide() label = self.attr_labels[box_index] label.setY(y - 15 - label.boundingRect().height()) if self.show_annotations: label.hide() else: stat = self.stats[box_index] if self.compare == OWBoxPlot.CompareMedians and \ stat.median is not None: pos = stat.median + 5 / self.scale_x elif self.compare == OWBoxPlot.CompareMeans or stat.q25 is None: pos = stat.mean + 5 / self.scale_x else: pos = stat.q25 label.setX(pos * self.scale_x) label.show() r = QRectF(self.scene_min_x, -30 - len(self.stats) * heights, self.scene_width, len(self.stats) * heights + 90) self.box_scene.setSceneRect(r) self._compute_tests_cont() self._show_posthoc()
class PartItem(QGraphicsPathItem): COLOR = NotImplemented TIP_LEN = 13 def __init__(self, value: float, label: Tuple[str, float], norm_value: float): super().__init__() color = QColor(*self.light_rgb) self.value = value self.norm_value = norm_value self.setPath(self.get_path()) pen = QPen(color) pen.setWidth(2) self.setPen(pen) value = np.abs(value) self.value_item = item = QGraphicsSimpleTextItem(_str(value)) item.setToolTip(_str(value, 3)) font = item.font() font.setPixelSize(11) item.setFont(font) width = item.boundingRect().width() item.setX(StripeItem.WIDTH / 2 - width / 2) item.setPen(color) item.setBrush(color) self.label_item = QGraphicsSimpleTextItem( f"{label[0]} = {_str(label[1])}") self.label_item.setToolTip(f"{label[0]} = {_str(label[1], 3)}") self.label_item.setX(StripeItem.WIDTH + StripePlot.SPACING) @property def light_rgb(self) -> List[int]: rgb = np.array(self.COLOR) return list((rgb + (255 - rgb) * 0.7).astype(int)) @property def value_height(self) -> float: return self.value_item.boundingRect().height() @property def label_height(self) -> float: return self.label_item.boundingRect().height() def get_path(self) -> QPainterPath: raise NotImplementedError
def pie_label(self, x, y, label): if not label: return text = QGraphicsSimpleTextItem(label) for cut in range(1, len(label)): if text.boundingRect().width() < 0.95 * SCALE: break text = QGraphicsSimpleTextItem(label[:-cut] + "...") text.setPos(x - text.boundingRect().width() / 2, y + 0.5 * SCALE) self.scene.addItem(text)
def draw_stat(self): if self.stat_test: label = QGraphicsSimpleTextItem(self.stat_test) label.setPos((self.scene_min_x + self.scene_max_x)/2 - label.boundingRect().width()/2, 8 + self._axis_font.pixelSize()*2) label.setFlag(QGraphicsItem.ItemIgnoresTransformations) self.box_scene.addItem(label)
def __init__(self, name, values, scale, name_offset, offset, labels=None): super().__init__() # leading label font = name.document().defaultFont() if self.bold_label: font.setWeight(QFont.Bold) name.setFont(font) name.setPos(name_offset, -10) name.setParentItem(self) # prediction marker self.dot = self.DOT_ITEM_CLS(self.DOT_RADIUS, scale, offset, values[0], values[-1]) self.dot.setParentItem(self) # pylint: disable=unused-variable # line line = QGraphicsLineItem(min(values) * scale + offset, 0, max(values) * scale + offset, 0, self) if labels is None: labels = [str(abs(v) if v == -0 else v) for v in values] old_x_tick = None shown_items = [] w = QGraphicsSimpleTextItem(labels[0]).boundingRect().width() text_finish = values[0] * scale - w + offset - 10 for i, (label, value) in enumerate(zip(labels, values)): text = QGraphicsSimpleTextItem(label) x_text = value * scale - text.boundingRect().width() / 2 + offset if text_finish > x_text - 10: y_text, y_tick = self.DOT_RADIUS * 0.7, 0 text_finish = values[0] * scale + offset else: y_text = - text.boundingRect().height() - self.DOT_RADIUS * 0.7 y_tick = - self.tick_height text_finish = x_text + text.boundingRect().width() text.setPos(x_text, y_text) if not collides(text, shown_items): text.setParentItem(self) shown_items.append(text) x_tick = value * scale - self.tick_width / 2 + offset tick = QGraphicsRectItem( x_tick, y_tick, self.tick_width, self.tick_height, self) tick.setBrush(QColor(Qt.black)) if self.half_tick_height and i: x = x_tick - (x_tick - old_x_tick) / 2 half_tick = QGraphicsLineItem(x, - self.half_tick_height, x, 0, self) old_x_tick = x_tick
def centered_text(val, pos): t = QGraphicsSimpleTextItem( "%.*f" % (attr.number_of_decimals + 1, val), labels) t.setFont(self._label_font) bbox = t.boundingRect() t.setPos(pos - bbox.width() / 2, 22) return t
def _display_changed_disc(self): self.clear_scene() self.attr_labels = [ QGraphicsSimpleTextItem(lab) for lab in self.label_txts_all ] if not self.show_stretched: if self.group_var: self.labels = [ QGraphicsTextItem("{}".format(int(sum(cont)))) for cont in self.conts.array_with_unknowns if np.sum(cont) > 0 ] else: self.labels = [QGraphicsTextItem(str(int(sum(self.dist))))] self.order = list(range(len(self.attr_labels))) self.draw_axis_disc() if self.group_var: conts = self.conts.array_with_unknowns self.boxes = [ self.strudel(cont, val) for cont, val in zip(conts, self.group_var.values + ("", )) if np.sum(cont) > 0 ] sums_ = np.sum(conts, axis=1) sums_ = sums_[sums_ > 0] # only bars with sum > 0 are shown if self.sort_freqs: # pylint: disable=invalid-unary-operand-type self.order = sorted(self.order, key=(-sums_).__getitem__) else: conts = self.dist.array_with_unknowns self.boxes = [self.strudel(conts)] sums_ = [np.sum(conts)] for row, box_index in enumerate(self.order): y = (-len(self.boxes) + row) * 40 + 10 box = self.boxes[box_index] bars, labels = box[::2], box[1::2] self.__draw_group_labels(y, box_index) if not self.show_stretched: self.__draw_row_counts(y, self.labels[box_index], sums_[box_index]) if self.show_labels and self.attribute is not self.group_var: self.__draw_bar_labels(y, bars, labels) self.__draw_bars(y, bars) self.box_scene.setSceneRect( -self.label_width - 5, -30 - len(self.boxes) * 40, self.scene_width, len(self.boxes * 40) + 90, ) self._compute_tests_disc()
def __setup(self): self.__clear() font = self.font() group = QGraphicsItemGroup(self) for text in self.__items: t = QGraphicsSimpleTextItem(text, group) t.setData(0, text) t.setFont(font) t.setToolTip(text) self.__textitems.append(t)
def draw_stat(self): if self.stat_test: label = QGraphicsSimpleTextItem(self.stat_test) brect = self.box_scene.sceneRect() label.setPos( brect.center().x() - label.boundingRect().width() / 2, 8 + self._axis_font.pixelSize() * 2, ) label.setFlag(QGraphicsItem.ItemIgnoresTransformations) self.box_scene.addItem(label)
def display_changed_disc(self): self.clear_scene() self.attr_labels = [ QGraphicsSimpleTextItem(lab) for lab in self.label_txts_all ] if not self.stretched: if self.group_var: self.labels = [ QGraphicsTextItem("{}".format(int(sum(cont)))) for cont in self.conts ] else: self.labels = [QGraphicsTextItem(str(int(sum(self.dist))))] self.draw_axis_disc() if self.group_var: self.boxes = [ self.strudel(cont, i) for i, cont in enumerate(self.conts) ] else: self.boxes = [self.strudel(self.dist)] for row, box in enumerate(self.boxes): y = (-len(self.boxes) + row) * 40 + 10 label = self.attr_labels[row] b = label.boundingRect() label.setPos(-b.width() - 10, y - b.height() / 2) self.box_scene.addItem(label) if not self.stretched: label = self.labels[row] b = label.boundingRect() if self.group_var: right = self.scale_x * sum(self.conts[row]) else: right = self.scale_x * sum(self.dist) label.setPos(right + 10, y - b.height() / 2) self.box_scene.addItem(label) if self.attribute is not self.group_var: for text_item, bar_part in zip(box.childItems()[1::2], box.childItems()[::2]): label = QGraphicsSimpleTextItem(text_item.toPlainText()) label.setPos(bar_part.boundingRect().x(), y - label.boundingRect().height() - 8) self.box_scene.addItem(label) for text_item in box.childItems()[1::2]: box.removeFromGroup(text_item) for item in box.childItems(): self.box_scene.addItem(item) item.setPos(0, y) self.box_scene.setSceneRect(-self.label_width - 5, -30 - len(self.boxes) * 40, self.scene_width, len(self.boxes * 40) + 90) self.infot1.setText("") self.select_box_items()
def display_changed_disc(self): assert not self.is_continuous self.clear_scene() self.attr_labels = [ QGraphicsSimpleTextItem(lab) for lab in self.label_txts_all ] if not self.stretched: if self.group_var: self.labels = [ QGraphicsTextItem("{}".format(int(sum(cont)))) for cont in self.conts if np.sum(cont) > 0 ] else: self.labels = [QGraphicsTextItem(str(int(sum(self.dist))))] self.order = list(range(len(self.attr_labels))) self.draw_axis_disc() if self.group_var: self.boxes = \ [self.strudel(cont, i) for i, cont in enumerate(self.conts) if np.sum(cont) > 0] self.conts = self.conts[np.sum(np.array(self.conts), axis=1) > 0] if self.sort_freqs: # pylint: disable=invalid-unary-operand-type self.order = sorted( self.order, key=(-np.sum(self.conts, axis=1)).__getitem__) else: self.boxes = [self.strudel(self.dist)] for row, box_index in enumerate(self.order): y = (-len(self.boxes) + row) * 40 + 10 box = self.boxes[box_index] bars, labels = box[::2], box[1::2] self.__draw_group_labels(y, box_index) if not self.stretched: self.__draw_row_counts(y, box_index) if self.show_labels and self.attribute is not self.group_var: self.__draw_bar_labels(y, bars, labels) self.__draw_bars(y, bars) self.box_scene.setSceneRect(-self.label_width - 5, -30 - len(self.boxes) * 40, self.scene_width, len(self.boxes * 40) + 90) self.infot1.setText("") self.select_box_items()
def __init__(self, title, rank): super().__init__() self.setAcceptedMouseButtons(Qt.LeftButton) self.setCacheMode(self.DeviceCoordinateCache) self.setZValue(10) self.edges = [] self.name = title self.squares = GroupOfSquares(self) # Add text labels if len(title) > 20: title = title[:20] + '…' title = self.title = QGraphicsSimpleTextItem(title, self) subtitle = self.subtitle = QGraphicsSimpleTextItem('', self) self.rank = rank title.setFont(Node.Font.TITLE) subtitle.setFont(Node.Font.SUBTITLE) title.setZValue(12) subtitle.setZValue(11) # Set node's rect accoring to title size title = self.title.boundingRect() NODE_WIDTH, NODE_HEIGHT = 1.4, 3 self.setRect(-NODE_WIDTH / 2 * title.width(), -NODE_HEIGHT / 2 * title.height(), NODE_WIDTH * title.width(), NODE_HEIGHT * title.height()) self.selected = False
def display_changed_disc(self): assert not self.is_continuous self.clear_scene() self.attr_labels = [ QGraphicsSimpleTextItem(lab) for lab in self.label_txts_all ] if not self.stretched: if self.group_var: self.labels = [ QGraphicsTextItem("{}".format(int(sum(cont)))) for cont in self.conts if np.sum(cont) > 0 ] else: self.labels = [QGraphicsTextItem(str(int(sum(self.dist))))] self.draw_axis_disc() if self.group_var: self.boxes = \ [self.strudel(cont, i) for i, cont in enumerate(self.conts) if np.sum(cont) > 0] self.conts = self.conts[np.sum(np.array(self.conts), axis=1) > 0] else: self.boxes = [self.strudel(self.dist)] for row, box in enumerate(self.boxes): y = (-len(self.boxes) + row) * 40 + 10 bars, labels = box[::2], box[1::2] self.__draw_group_labels(y, row) if not self.stretched: self.__draw_row_counts(y, row) if self.show_labels and self.attribute is not self.group_var: self.__draw_bar_labels(y, bars, labels) self.__draw_bars(y, bars) self.box_scene.setSceneRect(-self.label_width - 5, -30 - len(self.boxes) * 40, self.scene_width, len(self.boxes * 40) + 90) self.infot1.setText("") self.select_box_items()
def __init__(self, rect=QRectF(-5, -5, 10, 10), view=None): super().__init__(rect) self.setCacheMode(self.DeviceCoordinateCache) self.setAcceptHoverEvents(True) self.setFlags(self.ItemIsMovable | self.ItemIsSelectable | self.ItemIgnoresTransformations | self.ItemIgnoresParentOpacity | self.ItemSendsGeometryChanges) self.setZValue(4) self.edges = [] self._radius = rect.width() / 2 self.__transform = view.transform # Add text labels label = self.label = QGraphicsSimpleTextItem('test', self) label.setVisible(False) label.setFlags(self.ItemIgnoresParentOpacity | self.ItemIgnoresTransformations) label.setZValue(3) view.scene().addItem(label)
def __init__(self, source, dest, view=None): super().__init__() self.setAcceptedMouseButtons(Qt.NoButton) self.setFlags(self.ItemIgnoresTransformations | self.ItemIgnoresParentOpacity) self.setZValue(1) self.setPen(QPen(Qt.gray, .7)) source.addEdge(self) dest.addEdge(self) self.source = source self.dest = dest self.__transform = view.transform # Add text labels label = self.label = QGraphicsSimpleTextItem('test', self) label.setVisible(False) label.setBrush(Qt.gray) label.setZValue(2) label.setFlags(self.ItemIgnoresParentOpacity | self.ItemIgnoresTransformations) view.scene().addItem(label) self.adjust()
def mean_label(self, stat, attr, val_name): label = QGraphicsItemGroup() t = QGraphicsSimpleTextItem(attr.str_val(stat.mean), label) t.setFont(self._label_font) bbox = t.boundingRect() w2, h = bbox.width() / 2, bbox.height() t.setPos(-w2, -h) tpm = QGraphicsSimpleTextItem( " \u00b1 " + "%.*f" % (attr.number_of_decimals + 1, stat.dev), label) tpm.setFont(self._label_font) tpm.setPos(w2, -h) if val_name: vnm = QGraphicsSimpleTextItem(val_name + ": ", label) vnm.setFont(self._label_font) vnm.setBrush(self._attr_brush) vb = vnm.boundingRect() label.min_x = -w2 - vb.width() vnm.setPos(label.min_x, -h) else: label.min_x = -w2 return label
def centered_text(val, pos): t = QGraphicsSimpleTextItem(attr.str_val(val), labels) t.setFont(self._label_font) bbox = t.boundingRect() t.setPos(pos - bbox.width() / 2, 22) return t
def replot_experiments(self): """Replot the whole quality plot. """ self.scene.clear() labels = [] max_dist = numpy.nanmax(list(filter(None, self.distances))) rug_widgets = [] group_pen = QPen(Qt.black) group_pen.setWidth(2) group_pen.setCapStyle(Qt.RoundCap) background_pen = QPen(QColor(0, 0, 250, 150)) background_pen.setWidth(1) background_pen.setCapStyle(Qt.RoundCap) main_widget = QGraphicsWidget() layout = QGraphicsGridLayout() attributes = self.data.domain.attributes if self.data is not None: for (group, indices), dist_vec in zip(self.groups, self.distances): indices_set = set(indices) rug_items = [] if dist_vec is not None: for i, attr in enumerate(attributes): # Is this a within group distance or background in_group = i in indices_set if in_group: rug_item = ClickableRugItem(dist_vec[i] / max_dist, 1.0, self.on_rug_item_clicked) rug_item.setPen(group_pen) tooltip = experiment_description(attr) rug_item.setToolTip(tooltip) rug_item.group_index = indices.index(i) rug_item.setZValue(rug_item.zValue() + 1) else: rug_item = ClickableRugItem(dist_vec[i] / max_dist, 0.85, self.on_rug_item_clicked) rug_item.setPen(background_pen) tooltip = experiment_description(attr) rug_item.setToolTip(tooltip) rug_item.group = group rug_item.index = i rug_item.in_group = in_group rug_items.append(rug_item) rug_widget = RugGraphicsWidget(parent=main_widget) rug_widget.set_rug(rug_items) rug_widgets.append(rug_widget) label = group_label(self.selected_split_by_labels(), group) label_item = QGraphicsSimpleTextItem(label, main_widget) label_item = GraphicsSimpleTextLayoutItem(label_item, parent=layout) label_item.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) labels.append(label_item) for i, (label, rug_w) in enumerate(zip(labels, rug_widgets)): layout.addItem(label, i, 0, Qt.AlignVCenter) layout.addItem(rug_w, i, 1) layout.setRowMaximumHeight(i, 30) main_widget.setLayout(layout) self.scene.addItem(main_widget) self.main_widget = main_widget self.rug_widgets = rug_widgets self.labels = labels self.on_view_resize(self.scene_view.size())
def mean_label(self, stat, attr, val_name): label = QGraphicsItemGroup() t = QGraphicsSimpleTextItem( "%.*f" % (attr.number_of_decimals + 1, stat.mean), label) t.setFont(self._label_font) bbox = t.boundingRect() w2, h = bbox.width() / 2, bbox.height() t.setPos(-w2, -h) tpm = QGraphicsSimpleTextItem( " \u00b1 " + "%.*f" % (attr.number_of_decimals + 1, stat.dev), label) tpm.setFont(self._label_font) tpm.setPos(w2, -h) if val_name: vnm = QGraphicsSimpleTextItem(val_name + ": ", label) vnm.setFont(self._label_font) vnm.setBrush(self._attr_brush) vb = vnm.boundingRect() label.min_x = -w2 - vb.width() vnm.setPos(label.min_x, -h) else: label.min_x = -w2 return label
def __init__(self, name, data_extremes, values, scale, name_offset, offset): super().__init__() data_start, data_stop = data_extremes[0], data_extremes[1] labels = [str(np.round(data_start + (data_stop - data_start) * i / (self.n_tck - 1), 1)) for i in range(self.n_tck)] # leading label font = name.document().defaultFont() name.setFont(font) name.setPos(name_offset, -10) name.setParentItem(self) # labels ascending = data_start < data_stop y_start, y_stop = (self.y_diff, 0) if ascending else (0, self.y_diff) for i in range(self.n_tck): text = QGraphicsSimpleTextItem(labels[i], self) w = text.boundingRect().width() y = y_start + (y_stop - y_start) / (self.n_tck - 1) * i text.setPos(-5 - w, y - 8) tick = QGraphicsLineItem(-2, y, 2, y, self) # prediction marker self.dot = Continuous2DMovableDotItem( self.DOT_RADIUS, scale, offset, values[0], values[-1], y_start, y_stop) self.dot.tooltip_labels = labels self.dot.tooltip_values = values self.dot.setParentItem(self) h_line = QGraphicsLineItem(values[0] * scale + offset, self.y_diff / 2, values[-1] * scale + offset, self.y_diff / 2, self) pen = QPen(Qt.DashLine) pen.setBrush(QColor(Qt.red)) h_line.setPen(pen) self.dot.horizontal_line = h_line # pylint: disable=unused-variable # line line = QGraphicsLineItem(values[0] * scale + offset, y_start, values[-1] * scale + offset, y_stop, self) # ticks for value in values: diff_ = np.nan_to_num(values[-1] - values[0]) k = (value - values[0]) / diff_ if diff_ else 0 y_tick = (y_stop - y_start) * k + y_start - self.tick_height / 2 x_tick = value * scale - self.tick_width / 2 + offset tick = QGraphicsRectItem( x_tick, y_tick, self.tick_width, self.tick_height, self) tick.setBrush(QColor(Qt.black)) # rect rect = QGraphicsRectItem( values[0] * scale + offset, -self.y_diff * 0.125, values[-1] * scale + offset, self.y_diff * 1.25, self) pen = QPen(Qt.DotLine) pen.setBrush(QColor(50, 150, 200, 255)) rect.setPen(pen) self.setPreferredSize(self.preferredWidth(), self.y_diff * 1.5)