class_docstr: Creates a heterogeneous graph from multiple pandas dataframes.
  
  Examples
  --------
  Let's say we have the following three pandas dataframes:
  
  User table ``users``:
  
  ===========  ===========  =======
  ``user_id``  ``country``  ``age``
  ===========  ===========  =======
  XYZZY        U.S.         25
  FOO          China        24
  BAR          China        23
  ===========  ===========  =======
  
  Game table ``games``:
  
  ===========  =========  ==============  ==================
  ``game_id``  ``title``  ``is_sandbox``  ``is_multiplayer``
  ===========  =========  ==============  ==================
  1            Minecraft  True            True
  2            Tetris 99  False           True
  ===========  =========  ==============  ==================
  
  Play relationship table ``plays``:
  
  ===========  ===========  =========
  ``user_id``  ``game_id``  ``hours``
  ===========  ===========  =========
  XYZZY        1            24
  FOO          1            20
  FOO          2            16
  BAR          2            28
  ===========  ===========  =========
  
  One could then create a bidirectional bipartite graph as follows:
  >>> builder = PandasGraphBuilder()
  >>> builder.add_entities(users, 'user_id', 'user')
  >>> builder.add_entities(games, 'game_id', 'game')
  >>> builder.add_binary_relations(plays, 'user_id', 'game_id', 'plays')
  >>> builder.add_binary_relations(plays, 'game_id', 'user_id', 'played-by')
  >>> g = builder.build()
  >>> g.num_nodes('user')
  3
  >>> g.num_edges('plays')
  4
code: def add_binary_relations(
      self, relation_table, source_key, destination_key, name
  ):
      src = relation_table[source_key].astype("category")
      src = src.cat.set_categories(
          self.entity_key_map[
              self.entity_pk_to_name[source_key]
          ].cat.categories
      )
      dst = relation_table[destination_key].astype("category")
      dst = dst.cat.set_categories(
          self.entity_key_map[
              self.entity_pk_to_name[destination_key]
          ].cat.categories
      )
      if src.isnull().any():
          raise ValueError(
              "Some source entities in relation %s do not exist in entity %s."
              % (name, source_key)
          )
      if dst.isnull().any():
          raise ValueError(
              "Some destination entities in relation %s do not exist in entity %s."
              % (name, destination_key)
          )
  
      srctype = self.entity_pk_to_name[source_key]
      dsttype = self.entity_pk_to_name[destination_key]
      etype = (srctype, name, dsttype)
      self.relation_name_to_etype[name] = etype
      self.edges_per_relation[etype] = (
          src.cat.codes.values.astype("int64"),
          dst.cat.codes.values.astype("int64"),
      )
      self.relation_tables[name] = relation_table
      self.relation_src_key[name] = source_key
      self.relation_dst_key[name] = destination_key
  
file_path: dgl/examples/pytorch/pinsage/builder.py
imports: from collections import namedtuple
  import dgl
  from pandas.api.types import is_categorical, is_categorical_dtype, is_numeric_dtype
label_desc: Use image node_id 3 for calling the PandasGraphBuilder obj's underlying member method code with example usage: obj.add_binary_relations(relation_table, source_key, destination_key, name) without return types