code: def nonlinear_sem_generator(
      graph: nx.DiGraph,
      kernel: Kernel = RBF(1),
      schema: Optional[Dict] = None,
      default_type: str = "continuous",
      noise_std: float = 1.0,
      n_samples: int = 1000,
      distributions: Dict[str, str] = None,
      seed: int = None,
  ) -> pd.DataFrame:
      """
      Generator for non-linear tabular data with mixed variable types from a DAG.
  
      The nonlinearity can be controlled via the ``kernel``. Note that a
      ``DotProduct`` is equivalent to a linear function (without mean).
  
      Supported variable types: `'binary', 'categorical', 'continuous'`. The number
      of categories can be determined using a colon, e.g. `'categorical:5'`
      specifies a categorical feature with 5 categories.
  
      Notation: For binary and continuous variables, a ``variable'' refers to a
      ``node'', a ``feature'' refers to the one-hot column for categorical
      variables and is equivalent to a binary or continuous variable.
  
      Args:
          graph: A DAG in form of a networkx or StructureModel.
          kernel: A kernel from sklearn.gaussian_process.kernels like RBF(1) or
              Matern(1) or any combinations thereof. The kernels are used to
              create the latent variable for the binary / categorical variables
              and are directly used for continuous variables.
          schema: Dictionary with schema for a node/variable, if a node is missing
              uses ``default_type``. Format, {node_name: variable type}.
          default_type: The default data type for a node/variable not listed
              in the schema, or when the schema is empty.
          noise_std: The standard deviation of the noise. The binary and
              categorical features are created using a latent variable approach.
              The noise standard deviation determines how much weight the "mean"
              estimate has on the feature value.
          n_samples: The number of rows/observations to sample.
          distributions:
              ``continuous'': The type of distribution to use for the noise
                  of a continuous variable. Options: 'gaussian'/'normal' (alias)
                  (default), 'student-t', 'exponential', 'gumbel'.
              ``binary'': The type of distribution to use for the noise
                  of the latent binary variable. Options: 'probit'/'normal' (alias),
                  'logit' (default).
              ``categorical'': The type of distribution to use for the noise
                  of a latent continuous feature. Options: 'probit'/'normal' (alias),
                  'logit'/'gumbel' (alias) (default).
          seed: Random State
  
      Returns:
          DataFrame with generated features, uses a one-hot coding for
          categorical features.
  
      Raises:
          ValueError: if the graph is not a DAG.
          ValueError: if schema variable type is not in `'binary', 'categorical',
              'continuous', 'continuous:X` (for variables with X categories).
          ValueError: if distributions['continuous'] is not 'gaussian', 'normal', 'student-t',
              'exponential', 'gumbel'.
          ValueError: if distributions['binary'] is not 'probit', 'normal', 'logit'.
          ValueError: if distributions['categorical'] is not 'probit', 'normal', 'logit', 'gumbel'.
          ValueError: if distributions['count'], the zero-inflation factor is not a float in [0, 1].
  
      Example:
          sm = StructureModel()
  
          sm.add_edges_from([('A', 'C'), ('D', 'C'), ('E', 'D')])
  
          sm.add_nodes_from(['B', 'F'])
  
          schema = {'B': 'binary', 'C': 'categorical:5',
                    'E': 'binary', 'F': 'continuous'}
  
          df = sem_generator(sm, schema, kernel=RBF(1), noise_scale=1,
                            n_samples=10000)
      """
      distributions, var_fte_mapper, x_mat = _init_sem_data_gen(
          graph=graph,
          schema=schema,
          n_samples=n_samples,
          default_type=default_type,
          distributions=distributions,
          seed=seed,
      )
  
      # loop over sorted features according to ancestry (no parents first)
      for j_node in nx.topological_sort(graph):
          # all feature indices corresponding to the node/variable
          j_idx_list = var_fte_mapper.get_indices(j_node)
  
          # get all parent feature indices for the variable/node
          parents_idx = var_fte_mapper.get_indices(
              list(graph.predecessors(j_node))
          )
  
          # if the data is a root node, must initialise the axis separate from noise parameter
          root_node = len(parents_idx) <= 0
  
          # continuous variable
          if var_fte_mapper.is_var_of_type(j_node, "continuous"):
              x_mat[:, j_idx_list[0]] = _add_continuous_noise(
                  mean=_gp_index(x_mat[:, parents_idx], kernel),
                  distribution=distributions["continuous"],
                  noise_std=noise_std,
                  root_node=root_node,
              )
  
          # binary variable
          elif var_fte_mapper.is_var_of_type(j_node, "binary"):
              x_mat[:, j_idx_list[0]] = _sample_binary_from_latent(
                  latent_mean=_gp_index(x_mat[:, parents_idx], kernel),
                  distribution=distributions["binary"],
                  noise_std=noise_std,
                  root_node=root_node,
              )
  
          # count
          if var_fte_mapper.is_var_of_type(j_node, "count"):
              x_mat[:, j_idx_list[0]] = _sample_count_from_latent(
                  eta=_gp_index(x_mat[:, parents_idx], kernel),
                  zero_inflation_pct=distributions["count"],
                  root_node=root_node,
              )
  
          # categorical variable
          elif var_fte_mapper.is_var_of_type(j_node, "categorical"):
              x_mat[:, j_idx_list] = _sample_categories_from_latent(
                  latent_mean=np.concatenate(
                      [
                          np.expand_dims(
                              _gp_index(x_mat[:, parents_idx], kernel),
                              axis=1,
                          )
                          for _ in j_idx_list
                      ],
                      axis=1,
                  ),
                  distribution=distributions["categorical"],
                  noise_std=noise_std,
                  root_node=root_node,
              )
      return pd.DataFrame(x_mat, columns=var_fte_mapper.feature_list)
  
imports: from typing import Dict, Hashable, List, Optional, Tuple, Union
  import networkx
  import numpy
  import pandas
  from sklearn.gaussian_process.kernels import RBF, Kernel
  from causalnex.structure import StructureModel
  from causalnex.structure.categorical_variable_mapper import VariableFeatureMapper, validate_schema
label_desc: Use image node_id 14 for calling a global function with example usage: nonlinear_sem_generator(graph, kernel, schema, default_type, noise_std, n_samples, distributions, seed) and returns: pd