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 _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 _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 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.setFlag(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 _add_feature_label(self): font = self.font() font.setPixelSize(11) item = QGraphicsSimpleTextItem("Feature value") item.setRotation(-90) item.setFont(font) item.setX(self.BAR_WIDTH + self.__offset * 2) item.setY(self.__bar_height / 2 + item.boundingRect().width() / 2) self.__group.addToGroup(item)
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 __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.setData(0, text) self.__textitems.append(t) group.setParentItem(self) self.__group = group
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 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 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 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
class VariableItem(QGraphicsItemGroup): MAX_ATTR_LEN = 25 MAX_LABEL_LEN = 150 VALUE_FONT_SETTING = {Updater.SIZE_LABEL: 12, Updater.IS_ITALIC_LABEL: True} 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) @property def items(self): return self.__name_item, self.__value_item def boundingRect(self): name_br = self.__name_item.boundingRect() width = name_br.width() height = name_br.height() if self.__value_item is not None: value_br = self.__value_item.boundingRect() width = max(width, value_br.width()) height += value_br.height() return QRectF(-width, 0, width, height) def updateGeometry(self): self.__elide() self.__align_center() self.__align_right() def set_max_len(self, length: int): self.__max_len = length self.updateGeometry() def _set_data(self, label: str): split = label.split("=") self.__name = split[0] self.__name_item.setToolTip(self.__name) self.updateGeometry() # align before adding to group self.addToGroup(self.__name_item) if len(split) > 1: self.__value = split[1] self.__value_item.setToolTip(self.__value) self.updateGeometry() # align before adding to group self.addToGroup(self.__value_item) def __elide(self): fm = QFontMetrics(self.__name_item.font()) text = fm.elidedText(self.__name, Qt.ElideRight, self.__max_len) self.__name_item.setText(text) if self.__value is not None: fm = QFontMetrics(self.__value_item.font()) text = fm.elidedText(self.__value, Qt.ElideRight, self.__max_len) self.__value_item.setText(text) def __align_center(self): if self.__value is not None: self.__value_item.setY(self.__name_item.boundingRect().height()) def __align_right(self): self.__name_item.setX(-self.__name_item.boundingRect().width()) if self.__value is not None: self.__value_item.setX(-self.__value_item.boundingRect().width())