def autorange_xy(img, axx, axy, data, xy_limits, xy_pad):
    """ Adjust axx and axy vertical range.

        xy_limits:
            None or "auto"   # matplotlib default range
            (min, max)       # vrange to specified values
            "data"           # vrange to min and max of data -/+ xy_pad
            "match"          # vrange to min and max of default ranges of each
            "clim"           # vrange to img.clim() -/+ xy_pad

        args:
            axx              # horizontal axis
            axy              # vertical axis
            data             # 2D numpy.ndarray
            xy_limits        # None or "auto" / (min, max) / "data" / "match" / "clim"
            xy_pad           # padding of the xy vertical range
                             # (active for xy_limits="data" or "clim")
        
        returns:
            axx, axy
    """
    # axx vertical range
    if xy_limits is None or xy_limits == "auto":
        pass
    elif isinstance(xy_limits, tuple):
        # values specified
        axx.set_ylim(*xy_limits)
        axy.set_xlim(*xy_limits)
    elif xy_limits == "data":
        # edge plots range to match padded data range
        rng = data.max() - data.min()
        limits = (data.min() - xy_pad * rng,
                  data.max() + xy_pad * rng)
        axx.set_ylim(*limits)
        axy.set_xlim(*limits)
    elif xy_limits == "match":
        # edge plots range to match each other
        limits = (min(axx.get_ylim()[0], axy.get_xlim()[0]),
                  max(axx.get_ylim()[1], axy.get_xlim()[1]))
        axx.set_ylim(*limits)
        axy.set_xlim(*limits)
    elif xy_limits == "clim":
        # edge plots range to match padded image clim
        clim = img.get_clim()
        rng = clim[1] - clim[0]
        limits = (clim[0] - xy_pad * rng,
                  clim[1] + xy_pad * rng)
        axx.set_ylim(*limits)
        axy.set_xlim(*limits)
    else:
        raise ValueError(f"Invalid value for `xy_limits`={xy_limits}")
    return axx, axy