dgl.to_heterogeneous(G, ntypes, etypes, ntype_field='_TYPE', etype_field='_TYPE', metagraph=None)[source]

Convert a homogeneous graph to a heterogeneous graph and return.

The input graph should have only one type of nodes and edges. Each node and edge stores an integer feature as its type ID (specified by ntype_field and etype_field). DGL uses it to retrieve the type names stored in the given ntypes and etypes arguments.

The function will automatically distinguish edge types that have the same given type IDs but different src and dst type IDs. For example, it allows both edges A and B to have the same type ID 0, but one has (0, 1) and the other as (2, 3) as the (src, dst) type IDs. In this case, the function will “split” edge type 0 into two types: (0, ty_A, 1) and (2, ty_B, 3). In another word, these two edges share the same edge type name, but can be distinguished by an edge type triplet.

The function stores the node and edge IDs in the input graph using the dgl.NID and dgl.EID names in the ndata and edata of the resulting graph. It also copies any node/edge features from G to the returned heterogeneous graph, except for reserved fields for storing type IDs (dgl.NTYPE and dgl.ETYPE) and node/edge IDs (dgl.NID and dgl.EID).

  • G (DGLGraph) – The homogeneous graph.

  • ntypes (list[str]) – The node type names.

  • etypes (list[str]) – The edge type names.

  • ntype_field (str, optional) – The feature field used to store node type. (Default: dgl.NTYPE)

  • etype_field (str, optional) – The feature field used to store edge type. (Default: dgl.ETYPE)

  • metagraph (networkx MultiDiGraph, optional) – Metagraph of the returned heterograph. If provided, DGL assumes that G can indeed be described with the given metagraph. If None, DGL will infer the metagraph from the given inputs, which could be costly for large graphs.


A heterogeneous graph.

Return type



The returned node and edge types may not necessarily be in the same order as ntypes and etypes.


The following example uses PyTorch backend.

>>> import dgl
>>> import torch
>>> hg = dgl.heterograph({
...     ('user', 'develops', 'activity'): (torch.tensor([0, 1]), torch.tensor([1, 2])),
...     ('developer', 'develops', 'game'): (torch.tensor([0, 1]), torch.tensor([0, 1]))
... })
>>> print(hg)
Graph(num_nodes={'activity': 3, 'developer': 2, 'game': 2, 'user': 2},
      num_edges={('developer', 'develops', 'game'): 2, ('user', 'develops', 'activity'): 2},
      metagraph=[('developer', 'game', 'develops'), ('user', 'activity', 'develops')])

We first convert the heterogeneous graph to a homogeneous graph.

>>> g = dgl.to_homogeneous(hg)
>>> print(g)
Graph(num_nodes=9, num_edges=4,
      ndata_schemes={'_TYPE': Scheme(shape=(), dtype=torch.int64),
                     '_ID': Scheme(shape=(), dtype=torch.int64)}
      edata_schemes={'_TYPE': Scheme(shape=(), dtype=torch.int64),
                     '_ID': Scheme(shape=(), dtype=torch.int64)})
>>> g.ndata
{'_TYPE': tensor([0, 0, 0, 1, 1, 2, 2, 3, 3]), '_ID': tensor([0, 1, 2, 0, 1, 0, 1, 0, 1])}
Nodes 0, 1, 2 for 'activity', 3, 4 for 'developer', 5, 6 for 'game', 7, 8 for 'user'
>>> g.edata
{'_TYPE': tensor([0, 0, 1, 1]), '_ID': tensor([0, 1, 0, 1])}
Edges 0, 1 for ('developer', 'develops', 'game'), 2, 3 for ('user', 'develops', 'activity')

Now convert the homogeneous graph back to a heterogeneous graph.

>>> hg_2 = dgl.to_heterogeneous(g, hg.ntypes, hg.etypes)
>>> print(hg_2)
Graph(num_nodes={'activity': 3, 'developer': 2, 'game': 2, 'user': 2},
      num_edges={('developer', 'develops', 'game'): 2, ('user', 'develops', 'activity'): 2},
      metagraph=[('developer', 'game', 'develops'), ('user', 'activity', 'develops')])

Retrieve the original node/edge IDs.

>>> hg_2.ndata[dgl.NID]
{'activity': tensor([0, 1, 2]),
 'developer': tensor([3, 4]),
 'game': tensor([5, 6]),
 'user': tensor([7, 8])}
>>> hg_2.edata[dgl.EID]
{('developer', 'develops', 'game'): tensor([0, 1]),
 ('user', 'develops', 'activity'): tensor([2, 3])}

See also