'Return the bounding range of all children.
[[xmin, xmax], [ymin, ymax]]
Values may be None if there are no specific bounds for an axis.'

def childrenBounds(self, frac=None, orthoRange=(None, None), items=None):

    profiler = debug.Profiler()
    if (items is None):
        items = self.addedItems
    (px, py) = [(v.length() if (v is not None) else 0) for v in self.childGroup.pixelVectors()]
    itemBounds = []
    for item in items:
        if (not item.isVisible()):
            continue
        useX = True
        useY = True
        if hasattr(item, 'dataBounds'):
            if (frac is None):
                frac = (1.0, 1.0)
            xr = item.dataBounds(0, frac=frac[0], orthoRange=orthoRange[0])
            yr = item.dataBounds(1, frac=frac[1], orthoRange=orthoRange[1])
            pxPad = (0 if (not hasattr(item, 'pixelPadding')) else item.pixelPadding())
            if ((xr is None) or ((xr[0] is None) and (xr[1] is None)) or np.isnan(xr).any() or np.isinf(xr).any()):
                useX = False
                xr = (0, 0)
            if ((yr is None) or ((yr[0] is None) and (yr[1] is None)) or np.isnan(yr).any() or np.isinf(yr).any()):
                useY = False
                yr = (0, 0)
            bounds = QtCore.QRectF(xr[0], yr[0], (xr[1] - xr[0]), (yr[1] - yr[0]))
            bounds = self.mapFromItemToView(item, bounds).boundingRect()
            if (not any([useX, useY])):
                continue
            if (useX != useY):
                ang = round(item.transformAngle())
                if ((ang == 0) or (ang == 180)):
                    pass
                elif ((ang == 90) or (ang == 270)):
                    (useX, useY) = (useY, useX)
                else:
                    continue
            itemBounds.append((bounds, useX, useY, pxPad))
        else:
            if (int((item.flags() & item.ItemHasNoContents)) > 0):
                continue
            else:
                bounds = item.boundingRect()
            bounds = self.mapFromItemToView(item, bounds).boundingRect()
            itemBounds.append((bounds, True, True, 0))
    range = [None, None]
    for (bounds, useX, useY, px) in itemBounds:
        if useY:
            if (range[1] is not None):
                range[1] = [min(bounds.top(), range[1][0]), max(bounds.bottom(), range[1][1])]
            else:
                range[1] = [bounds.top(), bounds.bottom()]
        if useX:
            if (range[0] is not None):
                range[0] = [min(bounds.left(), range[0][0]), max(bounds.right(), range[0][1])]
            else:
                range[0] = [bounds.left(), bounds.right()]
        profiler()
    w = self.width()
    h = self.height()
    if ((w > 0) and (range[0] is not None)):
        pxSize = ((range[0][1] - range[0][0]) / w)
        for (bounds, useX, useY, px) in itemBounds:
            if ((px == 0) or (not useX)):
                continue
            range[0][0] = min(range[0][0], (bounds.left() - (px * pxSize)))
            range[0][1] = max(range[0][1], (bounds.right() + (px * pxSize)))
    if ((h > 0) and (range[1] is not None)):
        pxSize = ((range[1][1] - range[1][0]) / h)
        for (bounds, useX, useY, px) in itemBounds:
            if ((px == 0) or (not useY)):
                continue
            range[1][0] = min(range[1][0], (bounds.top() - (px * pxSize)))
            range[1][1] = max(range[1][1], (bounds.bottom() + (px * pxSize)))
    return range
