code: def tile_with_columns(cls, op):
      in_df = op.inputs[0]
      out_df = op.outputs[0]
      col_names = op.col_names
      chunk_meta_lazy = is_chunk_meta_lazy(in_df.chunks[0])
      if out_df.ndim < 2:
          # Series
          column_index = calc_columns_index(col_names, in_df)[0]
          out_chunks = []
          dtype = in_df.dtypes[col_names]
          out_nsplits = (in_df.nsplits[0],)
          for i in range(in_df.chunk_shape[0]):
              c = in_df.cix[(i, column_index)]
              chunk_op = DataFrameIndex(col_names=col_names)
              if chunk_meta_lazy:
                  out_chunk = chunk_op.new_chunk(
                      [c],
                      shape=(c.shape[0],),
                      index=(i,),
                      dtype=dtype,
                      name=col_names,
                  )
                  out_chunk._set_tileable_meta(
                      tileable_key=out_df.key,
                      nsplits=out_nsplits,
                      index_value=out_df.index_value,
                  )
              else:
                  out_chunk = chunk_op.new_chunk(
                      [c],
                      shape=(c.shape[0],),
                      index=(i,),
                      dtype=dtype,
                      index_value=c.index_value,
                      name=col_names,
                  )
              out_chunks.append(out_chunk)
          new_op = op.copy()
          params = out_df.params.copy()
          params["chunks"] = out_chunks
          params["nsplits"] = out_nsplits
          return new_op.new_seriess(op.inputs, kws=[params])
      else:
          # combine columns into one chunk and keep the columns order at the same time.
          # When chunk columns are ['c1', 'c2', 'c3'], ['c4', 'c5'],
          # selected columns are ['c2', 'c3', 'c4', 'c2'], `column_splits` will be
          # [(['c2', 'c3'], 0), ('c4', 1), ('c2', 0)].
          if not isinstance(col_names, _list_like_types):
              col_names = [col_names]
          selected_index = [
              calc_columns_index(col, in_df) for col in col_names
          ]
          selected_index = list(
              itertools.chain.from_iterable(selected_index)
          )
          condition = np.where(np.diff(selected_index))[0] + 1
          column_splits = np.split(col_names, condition)
          column_indexes = np.split(selected_index, condition)
  
          out_chunks = [[] for _ in range(in_df.chunk_shape[0])]
          nsplits = [in_df.nsplits[0], []]
          column_nsplits = nsplits[1]
          for i, (columns, column_idx) in enumerate(
              zip(column_splits, column_indexes)
          ):
              try:
                  dtypes = in_df.dtypes[columns]
              except ValueError:  # pragma: no cover
                  dtypes = in_df.dtypes[list(columns)]
              column_nsplits.append(len(dtypes))
              for j in range(in_df.chunk_shape[0]):
                  c = in_df.cix[(j, column_idx[0])]
                  index_op = DataFrameIndex(
                      col_names=list(columns),
                      output_types=[OutputType.dataframe],
                  )
                  if chunk_meta_lazy:
                      out_chunk = index_op.new_chunk(
                          [c],
                          shape=(c.shape[0], len(dtypes)),
                          index=(j, i),
                      )
                      out_chunk._set_tileable_meta(
                          tileable_key=out_df.key,
                          nsplits=nsplits,
                          index_value=out_df.index_value,
                          columns_value=out_df.columns_value,
                          dtypes=out_df.dtypes,
                      )
                  else:
                      out_chunk = index_op.new_chunk(
                          [c],
                          shape=(c.shape[0], len(dtypes)),
                          index=(j, i),
                          dtypes=dtypes,
                          index_value=c.index_value,
                          columns_value=parse_index(
                              pd.Index(dtypes.index), store_data=True
                          ),
                      )
                  out_chunks[j].append(out_chunk)
          out_chunks = [item for cl in out_chunks for item in cl]
          new_op = op.copy()
          params = out_df.params.copy()
          params["chunks"] = out_chunks
          params["nsplits"] = nsplits
          return new_op.new_dataframes(op.inputs, kws=[params])
  
imports: import itertools
  from numbers import Integral
  import pandas
  import numpy
  from ...None import opcodes
  from ...config import options
  from ...core import ENTITY_TYPE, OutputType, recursive_tile
  from ...serialization.serializables import AnyField, Int32Field, BoolField
  from ...tensor.core import TENSOR_TYPE, TENSOR_CHUNK_TYPE
  from ...tensor.datasource import tensor
  from ...utils import has_unknown_shape
  from ..align import align_dataframe_series, align_dataframe_dataframe
  from ..core import SERIES_TYPE, SERIES_CHUNK_TYPE, DATAFRAME_TYPE, DATAFRAME_CHUNK_TYPE, is_chunk_meta_lazy
  from ..merge import DataFrameConcat
  from ..operands import DataFrameOperand, DataFrameOperandMixin
  from ..utils import parse_index, in_range_index
  from .utils import calc_columns_index
label_desc: Use image node_id 6 for calling the DataFrameIndex obj's underlying member method code with example usage: obj.tile_with_columns(cls, op) and returns: new_op, new_op