Mask is a 2d boolean matrix. Scale is a 2d local scale matrix,
    as output by kscale(). It's the outer product of the kdists column
    vector produced by kdists.

def affinity(
        matrix,
        mask=None,
        scale=None,
):
    """
    Mask is a 2d boolean matrix. Scale is a 2d local scale matrix,
    as output by kscale(). It's the outer product of the kdists column
    vector produced by kdists.
    """

    mask = (mask if mask is not None else np.ones(matrix.shape, dtype=bool))
    assert isconnected(mask)
    scale = (scale if scale is not None else np.ones(matrix.shape))

    ix = np.where(np.logical_not(mask))
    scaled_matrix = -matrix ** 2 / scale
    # inputs where distance = 0 and scale = 0 result in NaN:
    # the next line replaces NaNs with -1.0
    scaled_matrix[np.where(np.isnan(scaled_matrix))] = -1.0
    affinity_matrix = np.exp(scaled_matrix)
    affinity_matrix[ix] = 0.  # mask
    affinity_matrix.flat[::len(affinity_matrix) + 1] = 0.  # diagonal
    return affinity_matrix