For all text objects find alignment that causes the least overlap with
    points and other texts and apply it

def optimally_align_text(x, y, texts, expand, renderer=None, ax=None,
                         direction='xy'):
    """
    For all text objects find alignment that causes the least overlap with
    points and other texts and apply it
    """
    if ax is None:
        ax = plt.gca()
    if renderer is None:
        r = ax.get_figure().canvas.get_renderer()
    else:
        r = renderer
    bboxes = get_bboxes(texts, r, expand)
    if 'x' not in direction:
        ha = ['']
    else:
        ha = ['left', 'right', 'center']
    if 'y' not in direction:
        va = ['']
    else:
        va = ['bottom', 'top', 'center']
    alignment = list(product(ha, va))
    for i, text in enumerate(texts):
        counts = []
        for h, v in alignment:
            if h:
                text.set_ha(h)
            if v:
                text.set_va(v)
            bbox = text.get_window_extent(r).expanded(*expand).\
                transformed(ax.transData.inverted())
            c = get_points_inside_bbox(x, y, bbox)
            counts.append(len(c) + bbox.count_overlaps(bboxes) - 1)
        a = np.argmin(counts)
        if 'x' in direction:
            text.set_ha(alignment[a][0])
        if 'y' in direction:
            text.set_va(alignment[a][1])
        bboxes[i] = text.get_window_extent(r).expanded(*expand).\
            transformed(ax.transData.inverted())
    return texts