class_docstr: This transform takes a list of attributes names and if allowed, add them to x
  
  Example:
  
      Before calling "AddFeatsByKeys", if data.x was empty
  
      - transform: AddFeatsByKeys
        params:
            list_add_to_x: [False, True, True]
            feat_names: ['normal', 'rgb', "elevation"]
            input_nc_feats: [3, 3, 1]
  
      After calling "AddFeatsByKeys", data.x contains "rgb" and "elevation". Its shape[-1] == 4 (rgb:3 + elevation:1)
      If input_nc_feats was [4, 4, 1], it would raise an exception as rgb dimension is only 3.
  
  Paremeters
  ----------
  list_add_to_x: List[bool]
      For each boolean within list_add_to_x, control if the associated feature is going to be concatenated to x
  feat_names: List[str]
      The list of features within data to be added to x
  input_nc_feats: List[int], optional
      If provided, evaluate the dimension of the associated feature shape[-1] found using feat_names and this provided value. It allows to make sure feature dimension didn't change
  stricts: List[bool], optional
      Recommended to be set to list of True. If True, it will raise an Exception if feat isn't found or dimension doesn t match.
  delete_feats: List[bool], optional
      Wether we want to delete the feature from the data object. List length must match teh number of features added.
class_docstr_tok: ["This","transform","takes","a","list","of","attributes","names","and","if","allowed",",","add","them","to","x","Example",":","Before","calling","``","AddFeatsByKeys","''",",","if","data.x","was","empty","-","transform",":","AddFeatsByKeys","params",":","list_add_to_x",":","[","False",",","True",",","True","]","feat_names",":","[","'normal","'",",","'rgb","'",",","``","elevation","''","]","input_nc_feats",":","[","3",",","3",",","1","]","After","calling","``","AddFeatsByKeys","''",",","data.x","contains","``","rgb","''","and","``","elevation","''",".","Its","shape","[","-1","]","==","4","(","rgb:3","+","elevation:1",")","If","input_nc_feats","was","[","4",",","4",",","1","]",",","it","would","raise","an","exception","as","rgb","dimension","is","only","3",".","Paremeters","--","--","--","--","--","list_add_to_x",":","List","[","bool","]","For","each","boolean","within","list_add_to_x",",","control","if","the","associated","feature","is","going","to","be","concatenated","to","x","feat_names",":","List","[","str","]","The","list","of","features","within","data","to","be","added","to","x","input_nc_feats",":","List","[","int","]",",","optional","If","provided",",","evaluate","the","dimension","of","the","associated","feature","shape","[","-1","]","found","using","feat_names","and","this","provided","value",".","It","allows","to","make","sure","feature","dimension","did","n't","change","stricts",":","List","[","bool","]",",","optional","Recommended","to","be","set","to","list","of","True",".","If","True",",","it","will","raise","an","Exception","if","feat","is","n't","found","or","dimension","doesn","t","match",".","delete_feats",":","List","[","bool","]",",","optional","Wether","we","want","to","delete","the","feature","from","the","data","object",".","List","length","must","match","teh","number","of","features","added","."]
code: def __init__(
      self,
      list_add_to_x: List[bool],
      feat_names: List[str],
      input_nc_feats: List[Optional[int]] = None,
      stricts: List[bool] = None,
      delete_feats: List[bool] = None,
  ):
      self._feat_names = feat_names
      self._list_add_to_x = list_add_to_x
      self._delete_feats = delete_feats
      if self._delete_feats:
          assert len(self._delete_feats) == len(self._feat_names)
      from torch_geometric.transforms import Compose
  
      num_names = len(feat_names)
      if num_names == 0:
          raise Exception("Expected to have at least one feat_names")
  
      assert len(list_add_to_x) == num_names
  
      if input_nc_feats:
          assert len(input_nc_feats) == num_names
      else:
          input_nc_feats = [None for _ in range(num_names)]
  
      if stricts:
          assert len(stricts) == num_names
      else:
          stricts = [True for _ in range(num_names)]
  
      transforms = [
          AddFeatByKey(
              add_to_x,
              feat_name,
              input_nc_feat=input_nc_feat,
              strict=strict,
          )
          for add_to_x, feat_name, input_nc_feat, strict in zip(
              list_add_to_x, feat_names, input_nc_feats, stricts
          )
      ]
  
      self.transform = Compose(transforms)
  
imports: from typing import List, Optional
  from tqdm.auto import tqdm
  import itertools
  import numpy
  import math
  import re
  import torch
  import random
  from torch.nn import functional
  from functools import partial
  from torch_geometric.nn import fps, radius, knn, voxel_grid
  from torch_geometric.nn.pool.consecutive import consecutive_cluster
  from torch_geometric.nn.pool.pool import pool_pos, pool_batch
  from torch_scatter import scatter_add, scatter_mean
  from torch_geometric.data import Data, Batch
  from torch_points3d.datasets.multiscale_data import MultiScaleData
  from torch_points3d.utils.transform_utils import SamplingStrategy
  from torch_points3d.utils.config import is_list
  from torch_points3d.utils import is_iterable
  from torch_points3d.utils.geometry import euler_angles_to_rotation_matrix
label_desc: Use image node_id 1 to create a new AddFeatsByKeys object from inherited base classes: object with example: obj = AddFeatsByKeys(list_add_to_x, feat_names, input_nc_feats, stricts, delete_feats)