class_docstr: Test def add_cyclic(data, x=None, y=None, axis=-1,
                      cyclic=360, precision=1e-4):
  - variations of data, x, and y with and without axis keyword
  - different units of x - cyclic keyword
  - detection of cyclic points - precision keyword
  - error catching
docstr: Test cyclic keyword with axis data 4d, x 3d and y 2d
docstr_tok: ["Test","cyclic","keyword","with","axis","data","4d",",","x","3d","and","y","2d"]
code: def test_cyclic(self):
      """Test cyclic keyword with axis data 4d, x 3d and y 2d"""
      new_lons = np.deg2rad(self.lon3d)
      new_lats = np.deg2rad(self.lat2d)
      c_data, c_lons, c_lats = add_cyclic(
          self.data4d,
          x=new_lons,
          y=new_lats,
          axis=1,
          cyclic=np.deg2rad(360),
      )
      r_lons = np.concatenate(
          (
              new_lons,
              np.full(
                  (new_lons.shape[0], 1, new_lons.shape[2]),
                  np.deg2rad(360),
              ),
          ),
          axis=1,
      )
      r_lats = np.concatenate((new_lats, new_lats[:, -1:]), axis=1)
      assert_array_equal(c_data, self.c_data4d)
      assert_array_equal(c_lons, r_lons)
      assert_array_equal(c_lats, r_lats)
  
imports: import numpy
  import numpy.ma
  from numpy.testing import assert_array_equal
  import pytest
  from cartopy.util import add_cyclic, add_cyclic_point, has_cyclic
label_desc: Use image node_id 21 for calling the TestAddCyclic obj's underlying member method code with example usage: obj.test_cyclic() without return types