<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def get_variable_by_axis(self, var, axis, coords=None):
 """Return the coordinate matching the specified axis This method uses to ``'axis'`` attribute in coordinates to return the corresponding coordinate of the given variable Possible types var: xarray.Variable The variable to get the dimension for axis: {'x', 'y', 'z', 't'} The axis string that identifies the dimension coords: dict Coordinates to use. If None, the coordinates of the dataset in the :attr:`ds` attribute are used. Returns ------- xarray.Coordinate or None The coordinate for `var` that matches the given `axis` or None if no coordinate with the right `axis` could be found. Notes ----- This is a rather low-level function that only interpretes the CFConvention. It is used by the :meth:`get_x`, :meth:`get_y`, :meth:`get_z` and :meth:`get_t` methods Warning ------- If None of the coordinates have an ``'axis'`` attribute, we use the ``'coordinate'`` attribute of `var` (if existent). Since however the CF Conventions do not determine the order on how the coordinates shall be saved, we try to use a pattern matching for latitude (``'lat'``) and longitude (``lon'``). If this patterns do not match, we interpret the coordinates such that x: -1, y: -2, z: -3. This is all not very safe for awkward dimension names, but works for most cases. If you want to be a hundred percent sure, use the :attr:`x`, :attr:`y`, :attr:`z` and :attr:`t` attribute. See Also -------- get_x, get_y, get_z, get_t"""

        axis = axis.lower()
        if axis not in list('xyzt'):
            raise ValueError("Axis must be one of X, Y, Z, T, not {0}".format(
                axis))
        # we first check for the dimensions and then for the coordinates
        # attribute
        coords = coords or self.ds.coords
        coord_names = var.attrs.get('coordinates', var.encoding.get(
            'coordinates', '')).split()
        if not coord_names:
            return
        ret = []
        for coord in map(lambda dim: coords[dim], filter(
                lambda dim: dim in coords, chain(
                    coord_names, var.dims))):
            # check for the axis attribute or whether the coordinate is in the
            # list of possible coordinate names
            if (coord.name not in (c.name for c in ret) and
                    (coord.attrs.get('axis', '').lower() == axis or
                     coord.name in getattr(self, axis))):
                ret.append(coord)
        if ret:
            return None if len(ret) > 1 else ret[0]
        # If the coordinates attribute is specified but the coordinate
        # variables themselves have no 'axis' attribute, we interpret the
        # coordinates such that x: -1, y: -2, z: -3
        # Since however the CF Conventions do not determine the order on how
        # the coordinates shall be saved, we try to use a pattern matching
        # for latitude and longitude. This is not very nice, hence it is
        # better to specify the :attr:`x` and :attr:`y` attribute
        tnames = self.t.intersection(coord_names)
        if axis == 'x':
            for cname in filter(lambda cname: re.search('lon', cname),
                                coord_names):
                return coords[cname]
            return coords.get(coord_names[-1])
        elif axis == 'y' and len(coord_names) >= 2:
            for cname in filter(lambda cname: re.search('lat', cname),
                                coord_names):
                return coords[cname]
            return coords.get(coord_names[-2])
        elif (axis == 'z' and len(coord_names) >= 3 and
              coord_names[-3] not in tnames):
            return coords.get(coord_names[-3])
        elif axis == 't' and tnames:
            tname = next(iter(tnames))
            if len(tnames) > 1:
                warn("Found multiple matches for time coordinate in the "
                     "coordinates: %s. I use %s" % (', '.join(tnames), tname),
                     PsyPlotRuntimeWarning)
            return coords.get(tname)