code: def _tile_dataframe(cls, op):
      from ..indexing.iloc import DataFrameIlocGetItem
      from ..merge.concat import DataFrameConcat
  
      inp = op.input
      out = op.outputs[0]
      axis = op.axis
  
      out_chunks = []
      if op.freq is not None:
          cum_nsplit = [0] + np.cumsum(inp.nsplits[axis]).tolist()
          # shift index
          for c in inp.chunks:
              chunk_op = op.copy().reset_key()
              i = c.index[axis]
              start, end = cum_nsplit[i], cum_nsplit[i + 1]
              if axis == 0:
                  index_value = cls._get_index_value(
                      c.index_value, op.periods, op.freq
                  )
                  columns_value = c.columns_value
                  dtypes = c.dtypes
              else:
                  dtypes = out.dtypes.iloc[start:end]
                  columns_value = parse_index(
                      dtypes.index, store_data=True
                  )
                  index_value = c.index_value
              out_chunk = chunk_op.new_chunk(
                  [c],
                  index=c.index,
                  shape=c.shape,
                  index_value=index_value,
                  columns_value=columns_value,
                  dtypes=dtypes,
              )
              out_chunks.append(out_chunk)
      else:
          if np.isnan(np.sum(inp.nsplits[axis])):  # pragma: no cover
              yield
  
          # shift data
          inc = op.periods > 0
          cum_nsplit = [0] + np.cumsum(inp.nsplits[axis]).tolist()
          for j in range(inp.chunk_shape[1 - axis]):
              for i in range(inp.chunk_shape[axis]):
                  index = [None, None]
                  index[axis] = i
                  index[1 - axis] = j
                  index = tuple(index)
  
                  start, end = cum_nsplit[i], cum_nsplit[i + 1]
  
                  c = inp.cix[index]
                  to_concats = [c]
                  left = abs(op.periods)
                  prev_i = i - 1 if inc else i + 1
                  while (
                      left > 0 and 0 <= prev_i < inp.chunk_shape[axis]
                  ):
                      prev_index = [None, None]
                      prev_index[axis] = prev_i
                      prev_index[1 - axis] = j
                      prev_index = tuple(prev_index)
  
                      prev_chunk = inp.cix[prev_index]
                      size = min(prev_chunk.shape[axis], left)
                      left -= size
                      prev_i = prev_i - 1 if inc else prev_i + 1
  
                      if size == prev_chunk.shape[axis]:
                          to_concat = prev_chunk
                      else:
                          slcs = [slice(None)] * 2
                          slc = (
                              slice(-size, None) if inc else slice(size)
                          )
                          slcs[axis] = slc
                          slc_op = DataFrameIlocGetItem(indexes=slcs)
                          to_concat = slc_op.new_chunk([prev_chunk])
  
                      if inc:
                          to_concats.insert(0, to_concat)
                      else:
                          to_concats.append(to_concat)
  
                  if len(to_concats) == 1:
                      to_shift_chunk = to_concats[0]
                  else:
                      concat_op = DataFrameConcat(
                          axis=axis, output_types=[OutputType.dataframe]
                      )
                      to_shift_chunk = concat_op.new_chunk(to_concats)
  
                  chunk_op = op.copy().reset_key()
                  if axis == 1:
                      dtypes = out.dtypes.iloc[start:end]
                      columns_value = parse_index(
                          dtypes.index, store_data=True
                      )
                      index_value = c.index_value
                  else:
                      dtypes = c.dtypes
                      columns_value = c.columns_value
                      index_value = cls._get_index_value(
                          c.index_value, op.periods, op.freq
                      )
  
                  out_chunk = chunk_op.new_chunk(
                      [to_shift_chunk],
                      index=index,
                      shape=c.shape,
                      index_value=index_value,
                      columns_value=columns_value,
                      dtypes=dtypes,
                  )
                  out_chunks.append(out_chunk)
  
      params = out.params
      params["chunks"] = out_chunks
      params["nsplits"] = inp.nsplits
      new_op = op.copy()
      return new_op.new_tileables(op.inputs, kws=[params])
  
imports: import numpy
  import pandas
  from ...None import opcodes
  from ...core import OutputType
  from ...serialization.serializables import KeyField, AnyField, Int8Field, Int64Field
  from ...utils import has_unknown_shape, no_default, pd_release_version
  from ..operands import DataFrameOperand, DataFrameOperandMixin
  from ..utils import parse_index, build_df, build_series, validate_axis
label_desc: Use image node_id 12 for calling the DataFrameShift obj's underlying member method code with example usage: obj._tile_dataframe(cls, op) and returns: new_op