class_docstr: A plain python object modeling a heterogeneous graph with various
  attributes (Node types in :class:`HeteroGraph` require string type).
  
  Args:
      G (:class:`networkx.classes.graph`): A NetworkX graph object which
          contains features and labels for each node type and edge type.
      **kwargs: Keyworded argument list with keys such
          as :obj:`"node_feature"`, :obj:`"node_label"` and
          corresponding attributes.
class_docstr_tok: ["A","plain","python","object","modeling","a","heterogeneous","graph","with","various","attributes","(","Node","types","in",":","class",":","`","HeteroGraph","`","require","string","type",")",".","Args",":","G","(",":","class",":","`","networkx.classes.graph","`",")",":","A","NetworkX","graph","object","which","contains","features","and","labels","for","each","node","type","and","edge","type",".","*","*","kwargs",":","Keyworded","argument","list","with","keys","such","as",":","obj",":","`","``","node_feature","''","`",",",":","obj",":","`","``","node_label","''","`","and","corresponding","attributes","."]
docstr: Split the graph into len(split_ratio) graphs for node prediction.
  Internally this splits node indices, and the model will only compute
  loss for the embedding of nodes in each split graph.
  In edge classification, the whole graph is observed in train/val/test.
  Only split over edge_label_index.
docstr_tok: ["Split","the","graph","into","len","(","split_ratio",")","graphs","for","node","prediction",".","Internally","this","splits","node","indices",",","and","the","model","will","only","compute","loss","for","the","embedding","of","nodes","in","each","split","graph",".","In","edge","classification",",","the","whole","graph","is","observed","in","train\/val\/test",".","Only","split","over","edge_label_index","."]
code: def _split_edge(
      self,
      split_types: List[tuple],
      split_ratio: float,
      shuffle: bool = True,
  ):
      r"""
      Split the graph into len(split_ratio) graphs for node prediction.
      Internally this splits node indices, and the model will only compute
      loss for the embedding of nodes in each split graph.
      In edge classification, the whole graph is observed in train/val/test.
      Only split over edge_label_index.
      """
  
      if isinstance(split_types, list):
          for split_type in split_types:
              if split_type not in self.message_types:
                  raise TypeError(
                      "all split_type in split_types need to be in "
                      f"{self.message_type}, however split type: "
                      "{split_type} is in split_types."
                  )
      elif split_types is None:
          split_types = self.message_types
      else:
          if split_types not in self.message_types:
              raise TypeError(
                  f"split_types need to be in {self.message_type}, "
                  f"however split_types is: {split_types}."
              )
          else:
              split_types = [split_types]
  
      for split_type, num_edge_type in self.num_edges(
          split_types
      ).items():
          if num_edge_type < len(split_ratio):
              raise ValueError(
                  "In _split_edge number of edges of message_type: "
                  f"{split_type} is smaller than the number of splitted "
                  "parts."
              )
  
      split_graphs = []
      for _ in range(len(split_ratio)):
          graph_new = copy.copy(self)
          graph_new.edge_label_index = {}
          graph_new.edge_label = {}
          split_graphs.append(graph_new)
  
      for split_type in self.message_types:
          if split_type in split_types:
              split_type_edges_length = self.num_edges(split_type)
  
              if shuffle:
                  shuffled_edge_indices = torch.randperm(
                      split_type_edges_length
                  )
              else:
                  shuffled_edge_indices = torch.arange(
                      split_type_edges_length
                  )
  
              split_offset = 0
  
              # used to indicate whether default splitting results in
              # empty splitted graphs
              split_empty_flag = False
              edges_split_list = []
  
              for i, split_ratio_i in enumerate(split_ratio):
                  if i != len(split_ratio) - 1:
                      num_split_i = int(
                          split_ratio_i * split_type_edges_length
                      )
                      edges_split_i = shuffled_edge_indices[
                          split_offset : split_offset + num_split_i
                      ]
                      split_offset += num_split_i
                  else:
                      edges_split_i = shuffled_edge_indices[
                          split_offset:
                      ]
                  if edges_split_i.numel() == 0:
                      split_empty_flag = True
                      split_offset = 0
                      edges_split_list = []
                      break
                  edges_split_list.append(edges_split_i)
  
              if split_empty_flag:
                  for i, split_ratio_i in enumerate(split_ratio):
                      # perform `secure split` s.t. guarantees all splitted
                      # subgraph of a split type contains at least one node.
                      if i != len(split_ratio) - 1:
                          num_split_i = 1 + int(
                              split_ratio_i
                              * (
                                  split_type_edges_length
                                  - len(split_ratio)
                              )
                          )
                          edges_split_i = shuffled_edge_indices[
                              split_offset : split_offset + num_split_i
                          ]
                          split_offset += num_split_i
                      else:
                          edges_split_i = shuffled_edge_indices[
                              split_offset:
                          ]
                      edges_split_list.append(edges_split_i)
  
              for idx, edges_split_i in enumerate(edges_split_list):
                  split_graphs[idx].edge_label_index[
                      split_type
                  ] = self.edge_label_index[split_type][
                      :, edges_split_i
                  ]
                  split_graphs[idx].edge_label[
                      split_type
                  ] = self.edge_label[split_type][edges_split_i]
  
          else:
              for idx, graph in enumerate(split_graphs):
                  graph.edge_label_index[
                      split_type
                  ] = self.edge_label_index[split_type]
                  graph.edge_label[split_type] = self.edge_label[
                      split_type
                  ]
                  split_graphs[idx] = graph
      return split_graphs
  
imports: import math
  import copy
  import random
  import torch
  import networkx
  import numpy
  from deepsnap.graph import Graph
  from typing import Dict, List, Union
  import warnings
label_desc: Use image node_id 30 for calling the HeteroGraph obj's underlying member method code with example usage: obj._split_edge(split_types, split_ratio, shuffle) and returns: split_graphs