code: def split_frame(
      full=None,
      *,
      past=None,
      future=None,
      past_length=None,
      future_length=None,
      static=None,
      index=None,
      start=None,
      freq=None,
      tdims=None,
      metadata=None,
      default_tdim=-1,
  ):
      """Create a ``zebras.SplitFrame`` where columns can either be `past`,
      `future` or `full`, which spans both past and future.
  
      ``past_length`` and ``future_length`` is derived from the input data if
      possible or default to ``0`` in case no respective data is available. It is
      possible to set these values explicitly for enforcing consistency or to
      provide a length even though no time series spans that range.
  
      Parameters
      ----------
      full, optional
          Time series columns that span past and future.
      past, optional
          Time series columns that are past only.
      future, optional
          Time series columns that are future only.
      past_length, optional
          Set length of the past section, derived from data if not provided.
      future_length, optional
          Set length of the future section, derived from data if not provided.
      static, optional
          Values that are independent of time.
      index, optional
          A ``zebras.Periods`` object representing timestamps.
          Must have the same length as full range.
      start, optional
          The start time represented by a string (e.g., "2023-01-01"),
          or a ``zebras.Period`` object. An index will be constructed using
          this start time and the specified frequency
      freq, optional
          The frequency to use for constructing the index.
      tdims, optional
          A dictionary specifying the time dimension for each column, this
          applies to past, future and full.
      default_tdim, optional
          The default time dimension, by default -1
      metadata, optional
          A dictionary of metadata associated with the TimeFrame, by default None
      Returns
      -------
          A ``zebras.SplitFrame`` object.
      """
      full = valmap(np.array, maybe.unwrap_or_else(full, dict))
      past = valmap(np.array, maybe.unwrap_or_else(past, dict))
      future = valmap(np.array, maybe.unwrap_or_else(future, dict))
      static = valmap(np.array, maybe.unwrap_or_else(static, dict))
      tdims = maybe.unwrap_or_else(tdims, dict)
  
      # Resolve `past_length` and `future_length` if not directly set from
      # provided data. If no data is passed for either field, the value is still
      # `None` after this.
      if past_length is None and past:
          column = first(past)
          past_length = past[column].shape[
              tdims.get(column, default_tdim)
          ]
  
      if future_length is None and future:
          column = first(future)
          future_length = future[column].shape[
              tdims.get(column, default_tdim)
          ]
  
      if full:
          column = first(full)
          full_length = full[column].shape[
              tdims.get(column, default_tdim)
          ]
  
          if maybe.or_(past_length, future_length) is None:
              raise ValueError(
                  "Cannot determine past and future length if only "
                  "`full` is provided."
              )
      # No data and no lengths are passed
      elif maybe.or_(past_length, future_length) is None:
          past_length = 0
          future_length = 0
          full_length = 0
      else:
          # If past_length and/or future_length is provided, but no `full` data
          # is given, then we first resolve past and future length and then just
          # calculate full_length later.
          full_length = None
  
      if past_length is None:
          past_length = maybe.map_or(
              full_length,
              lambda fl: fl - future_length,
              0,
          )
      elif future_length is None:
          future_length = maybe.map_or(
              full_length,
              lambda fl: fl - past_length,
              0,
          )
      full_length = past_length + future_length
  
      # create copies to not mutate user provided dicts
      past = dict(past)
      future = dict(future)
  
      for name, data in full.items():
          tdim = tdims.get(name, default_tdim)
          assert data.shape[tdim] == full_length
  
          past_data, future_data = np.split(
              data, [past_length], axis=tdim
          )
          past[name] = past_data
          future[name] = future_data
  
      sf = SplitFrame(
          _past=past,
          _future=future,
          index=index,
          static=static,
          tdims=tdims,
          past_length=past_length,
          future_length=future_length,
          default_tdim=default_tdim,
          metadata=metadata,
      )
  
      if sf.index is None and start is not None:
          if freq is not None:
              start = period(start, freq)
  
          return sf.with_index(start.periods(len(sf)))
  
      return sf
  
imports: from __future__ import annotations
  import dataclasses
  import itertools
  from operator import itemgetter
  from typing import Optional, List
  import numpy
  from toolz import first, keymap, valmap, dissoc, merge
  from gluonts import maybe
  from gluonts.itertools import pluck_attr, rows_to_columns
  from ._base import Pad
  from ._period import Periods, period
  from ._repr import html_table
  from ._util import _replace
  from ._time_series import TimeSeries
  from ._time_frame import BatchTimeFrame, TimeFrame
label_desc: Use image node_id 1 for calling a global function with example usage: split_frame(full) and returns: sf, sf