'Add a simple Sankey diagram with flows at the same hierarchical level.
Return value is the instance of :class:`Sankey`.
Optional keyword arguments:
Keyword           Description
*patchlabel*      label to be placed at the center of the diagram
Note: *label* (not *patchlabel*) will be passed to
the patch through ``**kwargs`` and can be used to
create an entry in the legend.
*flows*           array of flow values
By convention, inputs are positive and outputs are
negative.
*orientations*    list of orientations of the paths
Valid values are 1 (from/to the top), 0 (from/to
the left or right), or -1 (from/to the bottom).  If
*orientations* == 0, inputs will break in from the
left and outputs will break away to the right.
*labels*          list of specifications of the labels for the flows
Each value may be *None* (no labels), \'\' (just
label the quantities), or a labeling string.  If a
single value is provided, it will be applied to all
flows.  If an entry is a non-empty string, then the
quantity for the corresponding flow will be shown
below the string.  However, if the *unit* of the
main diagram is None, then quantities are never
shown, regardless of the value of this argument.
*trunklength*     length between the bases of the input and output
groups
*pathlengths*     list of lengths of the arrows before break-in or
after break-away
If a single value is given, then it will be applied
to the first (inside) paths on the top and bottom,
and the length of all other arrows will be
justified accordingly.  The *pathlengths* are not
applied to the horizontal inputs and outputs.
*prior*           index of the prior diagram to which this diagram
should be connected
*connect*         a (prior, this) tuple indexing the flow of the
prior diagram and the flow of this diagram which
should be connected
If this is the first diagram or *prior* is *None*,
*connect* will be ignored.
*rotation*        angle of rotation of the diagram [deg]
*rotation* is ignored if this diagram is connected
to an existing one (using *prior* and *connect*).
The interpretation of the *orientations* argument
will be rotated accordingly (e.g., if *rotation*
== 90, an *orientations* entry of 1 means to/from
the left).
Valid kwargs are :meth:`matplotlib.patches.PathPatch` arguments:
%(Patch)s
As examples, ``fill=False`` and ``label=\'A legend entry\'``.
By default, ``facecolor=\'#bfd1d4\'`` (light blue) and
``linewidth=0.5``.
The indexing parameters (*prior* and *connect*) are zero-based.
The flows are placed along the top of the diagram from the inside out
in order of their index within the *flows* list or array.  They are
placed along the sides of the diagram from the top down and along the
bottom from the outside in.
If the sum of the inputs and outputs is nonzero, the discrepancy
will appear as a cubic Bezier curve along the top and bottom edges of
the trunk.
.. seealso::
:meth:`finish`'

@docstring.dedent_interpd
def add(self, patchlabel=u'', flows=None, orientations=None, labels=u'', trunklength=1.0, pathlengths=0.25, prior=None, connect=(0, 0), rotation=0, **kwargs):

    if (flows is None):
        flows = np.array([1.0, (-1.0)])
    else:
        flows = np.array(flows)
    n = flows.shape[0]
    if (rotation is None):
        rotation = 0
    else:
        rotation /= 90.0
    if (orientations is None):
        orientations = [0, 0]
    if (len(orientations) != n):
        raise ValueError((u'orientations    and    flows    must    have    the    same    length.\norientations    has    length    %d,    but    flows    has    length    %d.' % (len(orientations), n)))
    if ((labels != u'') and getattr(labels, u'__iter__', False)):
        if (len(labels) != n):
            raise ValueError((u'If    labels    is    a    list,    then    labels    and    flows    must    have    the    same    length.\nlabels    has    length    %d,    but    flows    has    length    %d.' % (len(labels), n)))
    else:
        labels = ([labels] * n)
    if (trunklength < 0):
        raise ValueError(u"trunklength    is    negative.\nThis    isn't    allowed,    because    it    would    cause    poor    layout.")
    if (np.abs(np.sum(flows)) > self.tolerance):
        verbose.report((u'The    sum    of    the    flows    is    nonzero    (%f).\nIs    the    system    not    at    steady    state?' % np.sum(flows)), u'helpful')
    scaled_flows = (self.scale * flows)
    gain = sum((max(flow, 0) for flow in scaled_flows))
    loss = sum((min(flow, 0) for flow in scaled_flows))
    if (not (0.5 <= gain <= 2.0)):
        verbose.report((u'The    scaled    sum    of    the    inputs    is    %f.\nThis    may    cause    poor    layout.\nConsider    changing    the    scale    so    that    the    scaled    sum    is    approximately    1.0.' % gain), u'helpful')
    if (not ((-2.0) <= loss <= (-0.5))):
        verbose.report((u'The    scaled    sum    of    the    outputs    is    %f.\nThis    may    cause    poor    layout.\nConsider    changing    the    scale    so    that    the    scaled    sum    is    approximately    1.0.' % gain), u'helpful')
    if (prior is not None):
        if (prior < 0):
            raise ValueError(u'The    index    of    the    prior    diagram    is    negative.')
        if (min(connect) < 0):
            raise ValueError(u'At    least    one    of    the    connection    indices    is    negative.')
        if (prior >= len(self.diagrams)):
            raise ValueError((u'The    index    of    the    prior    diagram    is    %d,    but    there    are    only    %d    other    diagrams.\nThe    index    is    zero-based.' % (prior, len(self.diagrams))))
        if (connect[0] >= len(self.diagrams[prior].flows)):
            raise ValueError((u'The    connection    index    to    the    source    diagram    is    %d,    but    that    diagram    has    only    %d    flows.\nThe    index    is    zero-based.' % (connect[0], len(self.diagrams[prior].flows))))
        if (connect[1] >= n):
            raise ValueError((u'The    connection    index    to    this    diagram    is    %d,    but    this    diagramhas    only    %d    flows.\n    The    index    is    zero-based.' % (connect[1], n)))
        if (self.diagrams[prior].angles[connect[0]] is None):
            raise ValueError((u'The    connection    cannot    be    made.        Check    that    the    magnitude    of    flow    %d    of    diagram    %d    is    greater    than    or    equal    to    the    specified    tolerance.' % (connect[0], prior)))
        flow_error = (self.diagrams[prior].flows[connect[0]] + flows[connect[1]])
        if (abs(flow_error) >= self.tolerance):
            raise ValueError((u'The    scaled    sum    of    the    connected    flows    is    %f,    which    is    not    within    the    tolerance    (%f).' % (flow_error, self.tolerance)))
    are_inputs = ([None] * n)
    for (i, flow) in enumerate(flows):
        if (flow >= self.tolerance):
            are_inputs[i] = True
        elif (flow <= (- self.tolerance)):
            are_inputs[i] = False
        else:
            verbose.report((u'The    magnitude    of    flow    %d    (%f)    is    below    the    tolerance    (%f).\nIt    will    not    be    shown,    and    it    cannot    be    used    in    a    connection.' % (i, flow, self.tolerance)), u'helpful')
    angles = ([None] * n)
    for (i, (orient, is_input)) in enumerate(zip(orientations, are_inputs)):
        if (orient == 1):
            if is_input:
                angles[i] = DOWN
            elif (not is_input):
                angles[i] = UP
        elif (orient == 0):
            if (is_input is not None):
                angles[i] = RIGHT
        else:
            if (orient != (-1)):
                raise ValueError((u'The    value    of    orientations[%d]    is    %d,    but    it    must    be    [    -1    |    0    |    1    ].' % (i, orient)))
            if is_input:
                angles[i] = UP
            elif (not is_input):
                angles[i] = DOWN
    if iterable(pathlengths):
        if (len(pathlengths) != n):
            raise ValueError((u'If    pathlengths    is    a    list,    then    pathlengths    and    flows    must    have    the    same    length.\npathlengths    has    length    %d,    but    flows    has    length    %d.' % (len(pathlengths), n)))
    else:
        urlength = pathlengths
        ullength = pathlengths
        lrlength = pathlengths
        lllength = pathlengths
        d = dict(RIGHT=pathlengths)
        pathlengths = [d.get(angle, 0) for angle in angles]
        for (i, (angle, is_input, flow)) in enumerate(zip(angles, are_inputs, scaled_flows)):
            if ((angle == DOWN) and is_input):
                pathlengths[i] = ullength
                ullength += flow
            elif ((angle == UP) and (not is_input)):
                pathlengths[i] = urlength
                urlength -= flow
        for (i, (angle, is_input, flow)) in enumerate(reversed(list(zip(angles, are_inputs, scaled_flows)))):
            if ((angle == UP) and is_input):
                pathlengths[((n - i) - 1)] = lllength
                lllength += flow
            elif ((angle == DOWN) and (not is_input)):
                pathlengths[((n - i) - 1)] = lrlength
                lrlength -= flow
        has_left_input = False
        for (i, (angle, is_input, spec)) in enumerate(reversed(list(zip(angles, are_inputs, zip(scaled_flows, pathlengths))))):
            if (angle == RIGHT):
                if is_input:
                    if has_left_input:
                        pathlengths[((n - i) - 1)] = 0
                    else:
                        has_left_input = True
        has_right_output = False
        for (i, (angle, is_input, spec)) in enumerate(zip(angles, are_inputs, list(zip(scaled_flows, pathlengths)))):
            if (angle == RIGHT):
                if (not is_input):
                    if has_right_output:
                        pathlengths[i] = 0
                    else:
                        has_right_output = True
    urpath = [(Path.MOVETO, [(self.gap - (trunklength / 2.0)), (gain / 2.0)]), (Path.LINETO, [((self.gap - (trunklength / 2.0)) / 2.0), (gain / 2.0)]), (Path.CURVE4, [((self.gap - (trunklength / 2.0)) / 8.0), (gain / 2.0)]), (Path.CURVE4, [(((trunklength / 2.0) - self.gap) / 8.0), ((- loss) / 2.0)]), (Path.LINETO, [(((trunklength / 2.0) - self.gap) / 2.0), ((- loss) / 2.0)]), (Path.LINETO, [((trunklength / 2.0) - self.gap), ((- loss) / 2.0)])]
    llpath = [(Path.LINETO, [((trunklength / 2.0) - self.gap), (loss / 2.0)]), (Path.LINETO, [(((trunklength / 2.0) - self.gap) / 2.0), (loss / 2.0)]), (Path.CURVE4, [(((trunklength / 2.0) - self.gap) / 8.0), (loss / 2.0)]), (Path.CURVE4, [((self.gap - (trunklength / 2.0)) / 8.0), ((- gain) / 2.0)]), (Path.LINETO, [((self.gap - (trunklength / 2.0)) / 2.0), ((- gain) / 2.0)]), (Path.LINETO, [(self.gap - (trunklength / 2.0)), ((- gain) / 2.0)])]
    lrpath = [(Path.LINETO, [((trunklength / 2.0) - self.gap), (loss / 2.0)])]
    ulpath = [(Path.LINETO, [(self.gap - (trunklength / 2.0)), (gain / 2.0)])]
    tips = np.zeros((n, 2))
    label_locations = np.zeros((n, 2))
    for (i, (angle, is_input, spec)) in enumerate(zip(angles, are_inputs, list(zip(scaled_flows, pathlengths)))):
        if ((angle == DOWN) and is_input):
            (tips[i, :], label_locations[i, :]) = self._add_input(ulpath, angle, *spec)
        elif ((angle == UP) and (not is_input)):
            (tips[i, :], label_locations[i, :]) = self._add_output(urpath, angle, *spec)
    for (i, (angle, is_input, spec)) in enumerate(reversed(list(zip(angles, are_inputs, list(zip(scaled_flows, pathlengths)))))):
        if ((angle == UP) and is_input):
            (tip, label_location) = self._add_input(llpath, angle, *spec)
            tips[((n - i) - 1), :] = tip
            label_locations[((n - i) - 1), :] = label_location
        elif ((angle == DOWN) and (not is_input)):
            (tip, label_location) = self._add_output(lrpath, angle, *spec)
            tips[((n - i) - 1), :] = tip
            label_locations[((n - i) - 1), :] = label_location
    has_left_input = False
    for (i, (angle, is_input, spec)) in enumerate(reversed(list(zip(angles, are_inputs, list(zip(scaled_flows, pathlengths)))))):
        if ((angle == RIGHT) and is_input):
            if (not has_left_input):
                if (llpath[(-1)][1][0] > ulpath[(-1)][1][0]):
                    llpath.append((Path.LINETO, [ulpath[(-1)][1][0], llpath[(-1)][1][1]]))
                has_left_input = True
            (tip, label_location) = self._add_input(llpath, angle, *spec)
            tips[((n - i) - 1), :] = tip
            label_locations[((n - i) - 1), :] = label_location
    has_right_output = False
    for (i, (angle, is_input, spec)) in enumerate(zip(angles, are_inputs, list(zip(scaled_flows, pathlengths)))):
        if ((angle == RIGHT) and (not is_input)):
            if (not has_right_output):
                if (urpath[(-1)][1][0] < lrpath[(-1)][1][0]):
                    urpath.append((Path.LINETO, [lrpath[(-1)][1][0], urpath[(-1)][1][1]]))
                has_right_output = True
            (tips[i, :], label_locations[i, :]) = self._add_output(urpath, angle, *spec)
    if (not has_left_input):
        ulpath.pop()
        llpath.pop()
    if (not has_right_output):
        lrpath.pop()
        urpath.pop()
    path = ((((urpath + self._revert(lrpath)) + llpath) + self._revert(ulpath)) + [(Path.CLOSEPOLY, urpath[0][1])])
    (codes, vertices) = list(zip(*path))
    vertices = np.array(vertices)
    def _get_angle(a, r):
        if (a is None):
            return None
        else:
            return (a + r)
    if (prior is None):
        if (rotation != 0):
            angles = [_get_angle(angle, rotation) for angle in angles]
            rotate = Affine2D().rotate_deg((rotation * 90)).transform_affine
            tips = rotate(tips)
            label_locations = rotate(label_locations)
            vertices = rotate(vertices)
        text = self.ax.text(0, 0, s=patchlabel, ha=u'center', va=u'center')
    else:
        rotation = (self.diagrams[prior].angles[connect[0]] - angles[connect[1]])
        angles = [_get_angle(angle, rotation) for angle in angles]
        rotate = Affine2D().rotate_deg((rotation * 90)).transform_affine
        tips = rotate(tips)
        offset = (self.diagrams[prior].tips[connect[0]] - tips[connect[1]])
        translate = Affine2D().translate(*offset).transform_affine
        tips = translate(tips)
        label_locations = translate(rotate(label_locations))
        vertices = translate(rotate(vertices))
        kwds = dict(s=patchlabel, ha=u'center', va=u'center')
        text = self.ax.text(*offset, **kwds)
    if False:
        print(u'llpath\n', llpath)
        print(u'ulpath\n', self._revert(ulpath))
        print(u'urpath\n', urpath)
        print(u'lrpath\n', self._revert(lrpath))
        (xs, ys) = list(zip(*vertices))
        self.ax.plot(xs, ys, u'go-')
    if rcParams[u'_internal.classic_mode']:
        fc = kwargs.pop(u'fc', kwargs.pop(u'facecolor', u'#bfd1d4'))
        lw = kwargs.pop(u'lw', kwargs.pop(u'linewidth', 0.5))
    else:
        fc = kwargs.pop(u'fc', kwargs.pop(u'facecolor', None))
        lw = kwargs.pop(u'lw', kwargs.pop(u'linewidth', None))
    if (fc is None):
        fc = six.next(self.ax._get_patches_for_fill.prop_cycler)[u'color']
    patch = PathPatch(Path(vertices, codes), fc=fc, lw=lw, **kwargs)
    self.ax.add_patch(patch)
    texts = []
    for (number, angle, label, location) in zip(flows, angles, labels, label_locations):
        if ((label is None) or (angle is None)):
            label = u''
        elif (self.unit is not None):
            quantity = ((self.format % abs(number)) + self.unit)
            if (label != u''):
                label += u'\n'
            label += quantity
        texts.append(self.ax.text(x=location[0], y=location[1], s=label, ha=u'center', va=u'center'))
    self.extent = (min(np.min(vertices[:, 0]), np.min(label_locations[:, 0]), self.extent[0]), max(np.max(vertices[:, 0]), np.max(label_locations[:, 0]), self.extent[1]), min(np.min(vertices[:, 1]), np.min(label_locations[:, 1]), self.extent[2]), max(np.max(vertices[:, 1]), np.max(label_locations[:, 1]), self.extent[3]))
    self.diagrams.append(Bunch(patch=patch, flows=flows, angles=angles, tips=tips, text=text, texts=texts))
    return self
