From 28e7d4d12c613f7ef7f22bee0300a0f7c95dfbe9 Mon Sep 17 00:00:00 2001 From: Ogi Moore Date: Tue, 9 Feb 2021 20:42:39 -0800 Subject: [PATCH] Fix Small Heights in ErrorBarItem (#1558) * Add arrayToQPath bit * No more moveTo or lineTo * Use better names than 'partial' * Implement feedback from reviewer --- pyqtgraph/functions.py | 29 ++++++++++++++ pyqtgraph/graphicsItems/ErrorBarItem.py | 53 ++++++++++++++----------- 2 files changed, 59 insertions(+), 23 deletions(-) diff --git a/pyqtgraph/functions.py b/pyqtgraph/functions.py index 321c9d6b..0281aacd 100644 --- a/pyqtgraph/functions.py +++ b/pyqtgraph/functions.py @@ -662,6 +662,35 @@ def affineSlice(data, shape, origin, vectors, axes, order=1, returnCoords=False, return output +def interweaveArrays(*args): + """ + Parameters + ---------- + + args : numpy.ndarray + series of 1D numpy arrays of the same length and dtype + + Returns + ------- + numpy.ndarray + A numpy array with all the input numpy arrays interwoven + + Examples + -------- + + >>> result = interweaveArrays(numpy.ndarray([0, 2, 4]), numpy.ndarray([1, 3, 5])) + >>> result + array([0, 1, 2, 3, 4, 5]) + """ + + size = sum(x.size for x in args) + result = np.empty((size,), dtype=args[0].dtype) + n = len(args) + for index, array in enumerate(args): + result[index::n] = array + return result + + def interpolateArray(data, x, default=0.0, order=1): """ N-dimensional interpolation similar to scipy.ndimage.map_coordinates. diff --git a/pyqtgraph/graphicsItems/ErrorBarItem.py b/pyqtgraph/graphicsItems/ErrorBarItem.py index b79da6f7..365f1d47 100644 --- a/pyqtgraph/graphicsItems/ErrorBarItem.py +++ b/pyqtgraph/graphicsItems/ErrorBarItem.py @@ -2,6 +2,7 @@ from ..Qt import QtGui, QtCore from .GraphicsObject import GraphicsObject from .. import getConfigOption from .. import functions as fn +import numpy as np __all__ = ['ErrorBarItem'] @@ -66,7 +67,6 @@ class ErrorBarItem(GraphicsObject): beam = self.opts['beam'] - height, top, bottom = self.opts['height'], self.opts['top'], self.opts['bottom'] if height is not None or top is not None or bottom is not None: ## draw vertical error bars @@ -82,23 +82,27 @@ class ErrorBarItem(GraphicsObject): y2 = y else: y2 = y + top - - for i in range(len(x)): - p.moveTo(x[i], y1[i]) - p.lineTo(x[i], y2[i]) - + + xs = fn.interweaveArrays(x, x) + y1_y2 = fn.interweaveArrays(y1, y2) + verticalLines = fn.arrayToQPath(xs, y1_y2, connect="pairs") + p.addPath(verticalLines) + if beam is not None and beam > 0: x1 = x - beam/2. x2 = x + beam/2. + + x1_x2 = fn.interweaveArrays(x1, x2) if height is not None or top is not None: - for i in range(len(x)): - p.moveTo(x1[i], y2[i]) - p.lineTo(x2[i], y2[i]) + y2s = fn.interweaveArrays(y2, y2) + topEnds = fn.arrayToQPath(x1_x2, y2s, connect="pairs") + p.addPath(topEnds) + if height is not None or bottom is not None: - for i in range(len(x)): - p.moveTo(x1[i], y1[i]) - p.lineTo(x2[i], y1[i]) - + y1s = fn.interweaveArrays(y1, y1) + bottomEnds = fn.arrayToQPath(x1_x2, y1s, connect="pairs") + p.addPath(bottomEnds) + width, right, left = self.opts['width'], self.opts['right'], self.opts['left'] if width is not None or right is not None or left is not None: ## draw vertical error bars @@ -115,21 +119,24 @@ class ErrorBarItem(GraphicsObject): else: x2 = x + right - for i in range(len(x)): - p.moveTo(x1[i], y[i]) - p.lineTo(x2[i], y[i]) - + ys = fn.interweaveArrays(y, y) + x1_x2 = fn.interweaveArrays(x1, x2) + ends = fn.arrayToQPath(x1_x2, ys, connect='pairs') + p.addPath(ends) + if beam is not None and beam > 0: y1 = y - beam/2. y2 = y + beam/2. + y1_y2 = fn.interweaveArrays(y1, y2) if width is not None or right is not None: - for i in range(len(x)): - p.moveTo(x2[i], y1[i]) - p.lineTo(x2[i], y2[i]) + x2s = fn.interweaveArrays(x2, x2) + rightEnds = fn.arrayToQPath(x2s, y1_y2, connect="pairs") + p.addPath(rightEnds) + if width is not None or left is not None: - for i in range(len(x)): - p.moveTo(x1[i], y1[i]) - p.lineTo(x1[i], y2[i]) + x1s = fn.interweaveArrays(x1, x1) + leftEnds = fn.arrayToQPath(x1s, y1_y2, connect="pairs") + p.addPath(leftEnds) self.path = p self.prepareGeometryChange()