def _draw_border(point_1, point_2, border_width, parent): pen = QPen(QColor(self.border_color)) pen.setCosmetic(True) pen.setWidth(border_width) line = QGraphicsLineItem(QLineF(point_1, point_2), parent) line.setPen(pen) return line
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)
def make_pen(brush=Qt.black, width=1, style=Qt.SolidLine, cap_style=Qt.SquareCap, join_style=Qt.BevelJoin, cosmetic=False): pen = QPen(brush) pen.setWidth(width) pen.setStyle(style) pen.setCapStyle(cap_style) pen.setJoinStyle(join_style) pen.setCosmetic(cosmetic) return pen
def show_pearson(rect, pearson, pen_width): """ Color the given rectangle according to its corresponding standardized Pearson residual. Args: rect (QRect): the rectangle being drawn pearson (float): signed standardized pearson residual pen_width (int): pen width (bolder pen is used for selection) """ r = rect.rect() x, y, w, h = r.x(), r.y(), r.width(), r.height() if w == 0 or h == 0: return r = b = 255 if pearson > 0: r = g = max(255 - 20 * pearson, 55) elif pearson < 0: b = g = max(255 + 20 * pearson, 55) else: r = g = b = 224 rect.setBrush(QBrush(QColor(r, g, b))) pen_color = QColor(255 * (r == 255), 255 * (g == 255), 255 * (b == 255)) pen = QPen(pen_color, pen_width) rect.setPen(pen) if pearson > 0: pearson = min(pearson, 10) dist = 20 - 1.6 * pearson else: pearson = max(pearson, -10) dist = 20 - 8 * pearson pen.setWidth(1) def _offseted_line(ax, ay): r = QGraphicsLineItem(x + ax, y + ay, x + (ax or w), y + (ay or h)) self.canvas.addItem(r) r.setPen(pen) ax = dist while ax < w: _offseted_line(ax, 0) ax += dist ay = dist while ay < h: _offseted_line(0, ay) ay += dist
def _change_pen(self): pen = QPen(self._pen) if self._in_subset and self._selected: color = QColor(self._pen.color()) color.setAlpha(255) pen.setWidth(4) pen.setColor(color) elif not self._in_subset and self._selected: color = QColor(self._pen.color()) color.setAlpha(255) pen.setColor(color) elif self._in_subset and not self._selected: pen.setWidth(4) self.setPen(pen) self.setSymbolPen(pen)
def paint(self, painter, option, widget=None): # Override the default selected appearance if self.isSelected(): option.state ^= QStyle.State_Selected rect = self.rect() # this must render before overlay due to order in which it's drawn super().paint(painter, option, widget) painter.save() pen = QPen(QColor(Qt.black)) pen.setWidth(4) pen.setJoinStyle(Qt.MiterJoin) painter.setPen(pen) painter.drawRect(rect.adjusted(2, 2, -2, -2)) painter.restore() else: super().paint(painter, option, widget)
def show_average(self): self.view_average_menu.setChecked(True) self.set_pen_colors() self.clear_graph() self.viewtype = AVERAGE if not self.data: return x = self.data_x if self.data: ysall = [] cinfo = [] selected_indices = np.full(self.data_size, False, dtype=bool) selected_indices[list(self.selected_indices)] = True dsplit = self._split_by_color_value(self.data) for colorv, indices in dsplit.items(): for part in [None, "subset", "selection"]: if part is None: part_selection = indices pen = self.pen_normal if np.any( self.subset_indices) else self.pen_subset elif part == "selection" and self.selection_type: part_selection = indices & selected_indices pen = self.pen_selected elif part == "subset": part_selection = indices & self.subset_indices pen = self.pen_subset if np.any(part_selection): ys = self.data.X[part_selection] std = np.nanstd(ys, axis=0) mean = np.nanmean(ys, axis=0) std = std[self.data_xsind] mean = mean[self.data_xsind] ysall.append(mean) penc = QPen(pen[colorv]) penc.setWidth(3) self.add_curve(x, mean, pen=penc) self.add_fill_curve(x, mean + std, mean - std, pen=penc) cinfo.append((colorv, part, part_selection)) self.curves.append((x, np.array(ysall))) self.multiple_curves_info = cinfo self.curves_cont.update() self.plot.vb.set_mode_panning()
def paint(self, p, opt, widget): if self.xData is None or len(self.xData) == 0: return p.setRenderHint(p.Antialiasing, True) p.setCompositionMode(p.CompositionMode_SourceOver) if self.widths is None: p.setPen(self.pen) for x0, y0, x1, y1 in zip(self.xData[::2], self.yData[::2], self.xData[1::2], self.yData[1::2]): p.drawLine(QLineF(x0, y0, x1, y1)) else: pen = QPen(self.pen) for x0, y0, x1, y1, w in zip(self.xData[::2], self.yData[::2], self.xData[1::2], self.yData[1::2], self.widths): pen.setWidth(w) p.setPen(pen) p.drawLine(QLineF(x0, y0, x1, y1))
def _change_pen(self): pen = QPen(self._pen) color = QColor(Qt.black) if self._selected and self.master.has_subset \ else QColor(self._pen.color()) if self._in_subset or self._selected: width = LinePlotStyle.SELECTED_LINE_WIDTH alpha = LinePlotStyle.SELECTED_LINE_ALPHA else: width = LinePlotStyle.UNSELECTED_LINE_WIDTH alpha = LinePlotStyle.UNSELECTED_LINE_ALPHA_WITH_SELECTION \ if self.master.has_subset or self.master.has_selection else \ LinePlotStyle.UNSELECTED_LINE_ALPHA pen.setWidth(width) color.setAlpha(alpha) pen.setColor(color) self.setPen(pen)
def __init__(self, parent): super().__init__(parent) self.__range = None # type: Tuple[float] self.__value_range = None # type: Tuple[float] self.__model_output = None # type: float self.__base_value = None # type: float self.__group = QGraphicsItemGroup(self) low_color, high_color = QColor(*RGB_LOW), QColor(*RGB_HIGH) self.__low_item = QGraphicsRectItem() self.__low_item.setPen(QPen(low_color)) self.__low_item.setBrush(QBrush(low_color)) self.__high_item = QGraphicsRectItem() self.__high_item.setPen(QPen(high_color)) self.__high_item.setBrush(QBrush(high_color)) self.__low_cover_item = LowCoverItem() self.__high_cover_item = HighCoverItem() pen = QPen(IndicatorItem.COLOR) pen.setStyle(Qt.DashLine) pen.setWidth(1) self.__model_output_line = QGraphicsLineItem() self.__model_output_line.setPen(pen) self.__base_value_line = QGraphicsLineItem() self.__base_value_line.setPen(pen) self.__model_output_ind = IndicatorItem("Model prediction: {}") self.__base_value_ind = IndicatorItem("Base value: {}\nThe average " "prediction for selected class.") self.__group.addToGroup(self.__low_item) self.__group.addToGroup(self.__high_item) self.__group.addToGroup(self.__low_cover_item) self.__group.addToGroup(self.__high_cover_item) self.__group.addToGroup(self.__model_output_line) self.__group.addToGroup(self.__base_value_line) self.__group.addToGroup(self.__model_output_ind) self.__group.addToGroup(self.__base_value_ind) self.__low_parts = [] # type: List[LowPartItem] self.__high_parts = [] # type: List[HighPartItem]
def _change_pen(self): pen = QPen(self._pen) if self._in_subset and self._selected: color = QColor(self._pen.color()) color.setAlpha(255) pen.setWidth(4) pen.setColor(color) elif not self._in_subset and self._selected: color = QColor(self._pen.color()) color.setAlpha(255) pen.setColor(color) elif self._in_subset and not self._selected: color = QColor(self._pen.color()) color.setAlpha(LinePlotColors.LIGHT_ALPHA) pen.setWidth(4) pen.setColor(color) else: color = QColor(self._pen.color()) color.setAlpha(LinePlotColors.LIGHT_ALPHA) pen.setColor(color) self.setPen(pen)
def update_pen(pen, brush=None, width=None, style=None, cap_style=None, join_style=None, cosmetic=None): pen = QPen(pen) if brush is not None: pen.setBrush(QBrush(brush)) if width is not None: pen.setWidth(width) if style is not None: pen.setStyle(style) if cap_style is not None: pen.setCapStyle(cap_style) if join_style is not None: pen.setJoinStyle(join_style) if cosmetic is not None: pen.setCosmetic(cosmetic) return pen
def show_average(self): if not self.data: return self.viewtype = AVERAGE self.clear_graph() x = self.data_x if self.data: ysall = [] subset_indices = [i for i, id in enumerate(self.data.ids) if id in self.subset_ids] dsplit = self._split_by_color_value(self.data) for colorv, indices in dsplit.items(): for part in ["everything", "subset", "selection"]: if part == "everything": ys = self.data_ys[indices] pen = self.pen_normal if subset_indices else self.pen_subset elif part == "selection" and self.selection_type: current_selected = sorted(set(self.selected_indices) & set(indices)) if not current_selected: continue ys = self.data_ys[current_selected] pen = self.pen_selected elif part == "subset": current_subset = sorted(set(subset_indices) & set(indices)) if not current_subset: continue ys = self.data_ys[current_subset] pen = self.pen_subset std = np.std(ys, axis=0) mean = np.mean(ys, axis=0) ysall.append(mean) penc = QPen(pen[colorv]) penc.setWidth(3) self.add_curve(x, mean, pen=penc) self.add_fill_curve(x, mean + std, mean - std, pen=penc) self.curves.append((x, np.array(ysall))) self.curves_cont.update()
def hoverLeaveEvent(self, event): pen = QPen(self.pen()) pen.setWidth(2) self.setPen(pen) return RugItem.hoverLeaveEvent(self, event)
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 _setup_plot(self): """Setup the plot with new curve data.""" assert self.data is not None data, domain = self.data, self.data.domain if is_discrete(domain.class_var): class_col_data, _ = data.get_column_view(domain.class_var) group_indices = [ np.flatnonzero(class_col_data == i) for i in range(len(domain.class_var.values)) ] else: group_indices = [np.arange(len(data))] X = np.arange(1, len(domain.attributes) + 1) groups = [] for i, indices in enumerate(group_indices): if self.classes: color = self.class_colors[i] else: color = QColor(Qt.darkGray) group_data = data[indices, :] plot_x, plot_y, connect = disconnected_curve_data(group_data.X, x=X) color.setAlpha(200) lightcolor = QColor(color.lighter(factor=150)) lightcolor.setAlpha(150) pen = QPen(color, 2) pen.setCosmetic(True) lightpen = QPen(lightcolor, 1) lightpen.setCosmetic(True) hoverpen = QPen(pen) hoverpen.setWidth(2) curve = pg.PlotCurveItem( x=plot_x, y=plot_y, connect=connect, pen=lightpen, symbolSize=2, antialias=True, ) self.graph.addItem(curve) hovercurves = [] for index, profile in zip(indices, group_data.X): hcurve = HoverCurve(x=X, y=profile, pen=hoverpen, antialias=True) hcurve.setToolTip('{}'.format(index)) hcurve._data_index = index hovercurves.append(hcurve) self.graph.addItem(hcurve) mean = np.nanmean(group_data.X, axis=0) meancurve = pg.PlotDataItem(x=X, y=mean, pen=pen, size=5, symbol="o", pxMode=True, symbolSize=5, antialias=True) hoverpen = QPen(hoverpen) hoverpen.setWidth(5) hc = HoverCurve(x=X, y=mean, pen=hoverpen, antialias=True) hc.setFlag(QGraphicsItem.ItemIsSelectable, False) self.graph.addItem(hc) self.graph.addItem(meancurve) self.legend_items.append(meancurve) q1, q2, q3 = np.nanpercentile(group_data.X, [25, 50, 75], axis=0) # TODO: implement and use a box plot item errorbar = pg.ErrorBarItem(x=X, y=mean, bottom=np.clip(mean - q1, 0, mean - q1), top=np.clip(q3 - mean, 0, q3 - mean), beam=0.5) self.graph.addItem(errorbar) groups.append( namespace(data=group_data, indices=indices, profiles=curve, hovercurves=hovercurves, mean=meancurve, boxplot=errorbar)) self.__groups = groups self.__update_visibility() self.__update_tooltips()
def _setup_plot(self): """Setup the plot with new curve data.""" assert self.data is not None data, domain = self.data, self.data.domain if is_discrete(domain.class_var): class_col_data, _ = data.get_column_view(domain.class_var) group_indices = [np.flatnonzero(class_col_data == i) for i in range(len(domain.class_var.values))] else: group_indices = [np.arange(len(data))] X = np.arange(1, len(domain.attributes)+1) groups = [] for i, indices in enumerate(group_indices): if self.classes: color = self.class_colors[i] else: color = QColor(Qt.darkGray) group_data = data[indices, :] plot_x, plot_y, connect = disconnected_curve_data(group_data.X, x=X) color.setAlpha(200) lightcolor = QColor(color.lighter(factor=150)) lightcolor.setAlpha(150) pen = QPen(color, 2) pen.setCosmetic(True) lightpen = QPen(lightcolor, 1) lightpen.setCosmetic(True) hoverpen = QPen(pen) hoverpen.setWidth(2) curve = pg.PlotCurveItem( x=plot_x, y=plot_y, connect=connect, pen=lightpen, symbolSize=2, antialias=True, ) self.graph.addItem(curve) hovercurves = [] for index, profile in zip(indices, group_data.X): hcurve = HoverCurve(x=X, y=profile, pen=hoverpen, antialias=True) hcurve.setToolTip('{}'.format(index)) hcurve._data_index = index hovercurves.append(hcurve) self.graph.addItem(hcurve) mean = np.nanmean(group_data.X, axis=0) meancurve = pg.PlotDataItem( x=X, y=mean, pen=pen, size=5, symbol="o", pxMode=True, symbolSize=5, antialias=True ) hoverpen = QPen(hoverpen) hoverpen.setWidth(5) hc = HoverCurve(x=X, y=mean, pen=hoverpen, antialias=True) hc.setFlag(QGraphicsItem.ItemIsSelectable, False) self.graph.addItem(hc) self.graph.addItem(meancurve) self.legend_items.append(meancurve) q1, q2, q3 = np.nanpercentile(group_data.X, [25, 50, 75], axis=0) # TODO: implement and use a box plot item errorbar = pg.ErrorBarItem( x=X, y=mean, bottom=np.clip(mean - q1, 0, mean - q1), top=np.clip(q3 - mean, 0, q3 - mean), beam=0.5 ) self.graph.addItem(errorbar) groups.append( namespace( data=group_data, indices=indices, profiles=curve, hovercurves=hovercurves, mean=meancurve, boxplot=errorbar) ) self.__groups = groups self.__update_visibility() self.__update_tooltips()
def paint(self, p, opt, widget): def get_arrows(): # Compute (n, 4) array of coordinates of arrows' ends # Arrows are at 15 degrees; length is 10, clipped to edge length x0, y0, x1, y1 = edge_coords.T arr_len = np.clip(lengths - sizes1 - w3, 0, 10) cos12 = arr_len * np.cos(np.pi / 12) sin12 = arr_len * np.sin(np.pi / 12) # cos(a ± 15) = cos(a) cos(15) ∓ sin(a) sin(15) tx = sins * (fx * sin12) x1a = x1 - coss * (fx * cos12) x2a = x1a - tx x1a += tx # sin(a ± 15) = sin(a) cos(15) ± sin(15) cos(a) ty = (fy * sin12) * coss y1a = y1 + sins * (fy * cos12) y2a = y1a - ty y1a += ty return np.vstack((x1a, y1a, x2a, y2a)).T def get_short_edge_coords(): # Compute the target-side coordinates of edges with arrows # Such edges are shorted by 8 pixels + width / 3 off = 8 + w3 return edge_coords[:, 2:] + (off * np.vstack((-fxcos, fysin))).T if self.xData is None or len(self.xData) == 0: return # Widths of edges, divided by 3; used for adjusting sizes w3 = (self.widths if self.widths is not None else self.pen.width()) / 3 # Sizes of source and target nodes; they are used for adjusting the # edge lengths, so we increase the sizes by edge widths / 3 sizes0, sizes1 = self.sizes[::2] + w3, self.sizes[1::2] + w3 # Coordinates of vertices for all end points (in real world) x0s, x1s = self.xData[::2], self.xData[1::2] y0s, y1s = self.yData[::2], self.yData[1::2] # Factors for transforming real-worlds coordinates into pixels fx = 1 / p.worldTransform().m11() fy = 1 / p.worldTransform().m22() # Computations of angles (lengths are also used to clip the arrows) # We need sine and cosine of angles, and never the actual angles. # Sine and cosine are compute as ratios in triangles rather than with # trigonometric functions diffx, diffy = (x1s - x0s) / fx, -(y1s - y0s) / fy lengths = np.sqrt(diffx**2 + diffy**2) arcs = lengths == 0 coss, sins = np.nan_to_num(diffx / lengths), np.nan_to_num(diffy / lengths) # A slower version of the above, with trigonometry # angles = np.arctan2(-(y1s - y0s) / fy, (x1s - x0s) / fx) # return np.cos(angles), np.sin(angles) # Sin and cos are mostly used as mulitplied with fx and fy; precompute fxcos, fysin = fx * coss, fy * sins # Coordinates of edges' end points: coordinates of vertices, adjusted # by sizes. When drawing arraws, the target coordinate is used for # the tip of the arrow, not the edge edge_coords = np.vstack((x0s + fxcos * sizes0, y0s - fysin * sizes0, x1s - fxcos * sizes1, y1s + fysin * sizes1)).T pen = QPen(self.pen) p.setRenderHint(p.Antialiasing, True) p.setCompositionMode(p.CompositionMode_SourceOver) if self.widths is None: p.setPen(pen) if self.directed: for (x0, y0, x1, y1), (x1w, y1w), (xa1, ya1, xa2, ya2), arc in zip(edge_coords, get_short_edge_coords(), get_arrows(), arcs): if not arc: p.drawLine(QLineF(x0, y0, x1w, y1w)) p.drawLine(QLineF(xa1, ya1, x1, y1)) p.drawLine(QLineF(xa2, ya2, x1, y1)) else: for ecoords in edge_coords[~arcs]: p.drawLine(QLineF(*ecoords)) else: if self.directed: for (x0, y0, x1, y1), (x1w, y1w), (xa1, ya1, xa2, ya2), w, arc in zip(edge_coords, get_short_edge_coords(), get_arrows(), self.widths, arcs): if not arc: pen.setWidth(w) p.setPen(pen) p.drawLine(QLineF(x0, y0, x1w, y1w)) p.drawLine(QLineF(xa1, ya1, x1, y1)) p.drawLine(QLineF(xa2, ya2, x1, y1)) else: for ecoords, w in zip(edge_coords[~arcs], self.widths[~arcs]): pen.setWidth(w) p.setPen(pen) p.drawLine(QLineF(*ecoords)) # This part is not so optimized because there can't be that many loops if np.any(arcs): xs, ys = self.xData[::2][arcs], self.yData[1::2][arcs] sizes = self.sizes[::2][arcs] sizes += w3 if isinstance(w3, float) else w3[arcs] # if radius of loop would be size, then distance betwween # vertex and loop centers would be # d = np.sqrt(size ** 2 - r ** 2 / 2) + r / np.sqrt(2) + r / 2 ds = sizes * (1 + np.sqrt(2) / 4) rxs = xs - ds * fx rys = ys - ds * fy rfxs = sizes * fx rfys = sizes * fy ax0o = 6 * np.cos(np.pi * 5 / 6) * fx ax1o = 6 * np.cos(np.pi * 7 / 12) * fx ay0o = 6 * np.sin(np.pi * 5 / 6) * fy ay1o = 6 * np.sin(np.pi * 7 / 12) * fy if self.widths is None: widths = np.full(len(rxs), pen.width()) else: widths = self.widths[arcs] for rx, ry, rfx, rfy, w in zip(rxs, rys, rfxs, rfys, widths): rect = QRectF(rx, ry, rfx, rfy) pen.setWidth(w) p.setPen(pen) p.drawArc(rect, 100 * 16, 250 * 16) if self.directed: rx += 1.1 * rfx ry += rfy / 2 p.drawLine(QLineF(rx, ry, rx + ax0o, ry - ay0o)) p.drawLine(QLineF(rx, ry, rx + ax1o, ry - ay1o))
def paint(self, p, opt, widget): def get_arrows(): cos12 = 10 * np.cos(np.pi / 12) sin12 = 10 * np.sin(np.pi / 12) # cos(a ± 12) = cos(a) cos(12) ∓ sin(a) sin(12) tx = sins * (fx * sin12) xa1s = x1s - coss * (fx * cos12) xa2s = xa1s - tx xa1s += tx # sin(a ± 12) = sin(a) cos(12) ± sin(12) cos(a) ty = (fy * sin12) * coss ya1s = y1s + sins * (fy * cos12) ya2s = ya1s - ty ya1s += ty return xa1s, ya1s, xa2s, ya2s def get_angles(): angles = np.arctan2(-(y1s - y0s) / fy, (x1s - x0s) / fx) return np.cos(angles), np.sin(angles) """ # This below faster. Uncomment and check that it works diffx, diffy = (x1s - x0s) / fx, (y1s - y0s) / fy norm = np.sqrt(diffx ** 2 + diffy ** 2) self.coss = np.nan_to_num(diffx / norm) self.sins = np.nan_to_num(diffy / norm) """ def shorter_edges(): nonlocal x0s, x1s, y0s, y1s sizes0, sizes1 = self.sizes[::2], self.sizes[1::2] return (x0s + fx * sizes0 * coss, y0s - fy * sizes0 * sins, x1s - fx * sizes1 * coss, y1s + fy * sizes1 * sins) if self.xData is None or len(self.xData) == 0: return x0s, x1s = self.xData[::2], self.xData[1::2] y0s, y1s = self.yData[::2], self.yData[1::2] fx = 1 / p.worldTransform().m11() fy = 1 / p.worldTransform().m22() coss, sins = get_angles() endpoints = x0s, y0s, x1s, y1s = shorter_edges() p.setRenderHint(p.Antialiasing, True) p.setCompositionMode(p.CompositionMode_SourceOver) if self.widths is None: p.setPen(self.pen) if self.directed: for x0, y0, x1, y1, xa1, ya1, xa2, ya2 in zip( *endpoints, *get_arrows()): p.drawLine(QLineF(x0, y0, x1, y1)) p.drawLine(QLineF(xa1, ya1, x1, y1)) p.drawLine(QLineF(xa2, ya2, x1, y1)) else: for x0, y0, x1, y1 in zip(*endpoints): p.drawLine(QLineF(x0, y0, x1, y1)) else: pen = QPen(self.pen) if self.directed: for x0, y0, x1, y1, xa1, ya1, xa2, ya2, w in zip( *endpoints, *get_arrows(), self.widths): pen.setWidth(w) p.setPen(pen) p.drawLine(QLineF(x0, y0, x1, y1)) p.drawLine(QLineF(xa1, ya1, x1, y1)) p.drawLine(QLineF(xa2, ya2, x1, y1)) else: for x0, y0, x1, y1, w in zip(*endpoints, self.widths): pen.setWidth(w) p.setPen(pen) p.drawLine(QLineF(x0, y0, x1, y1))