code: def from_networkx(
      nx_graph,
      node_attrs=None,
      edge_attrs=None,
      edge_id_attr_name=None,
      idtype=None,
      device=None,
  ):
      """Create a graph from a NetworkX graph and return.
  
      .. note::
          Creating a DGLGraph from a NetworkX graph is not fast especially for large scales.
          It is recommended to first convert a NetworkX graph into a tuple of node-tensors
          and then construct a DGLGraph with :func:`dgl.graph`.
  
      Parameters
      ----------
      nx_graph : networkx.Graph
          The NetworkX graph holding the graph structure and the node/edge attributes.
          DGL will relabel the nodes using consecutive integers starting from zero if it is
          not the case. If the input graph is undirected, DGL converts it to a directed graph
          by :func:`networkx.Graph.to_directed`.
      node_attrs : list[str], optional
          The names of the node attributes to retrieve from the NetworkX graph. If given, DGL
          stores the retrieved node attributes in ``ndata`` of the returned graph using their
          original names. The attribute data must be convertible to Tensor type (e.g., scalar,
          numpy.ndarray, list, etc.).
      edge_attrs : list[str], optional
          The names of the edge attributes to retrieve from the NetworkX graph. If given, DGL
          stores the retrieved edge attributes in ``edata`` of the returned graph using their
          original names. The attribute data must be convertible to Tensor type (e.g., scalar,
          ``numpy.ndarray``, list, etc.). It must be None if :attr:`nx_graph` is undirected.
      edge_id_attr_name : str, optional
          The name of the edge attribute that stores the edge IDs. If given, DGL will assign edge
          IDs accordingly when creating the graph, so the attribute must be valid IDs, i.e.
          consecutive integers starting from zero. By default, the edge IDs of the returned graph
          can be arbitrary. It must be None if :attr:`nx_graph` is undirected.
      idtype : int32 or int64, optional
          The data type for storing the structure-related graph information such as node and
          edge IDs. It should be a framework-specific data type object (e.g., ``torch.int32``).
          By default, DGL uses int64.
      device : device context, optional
          The device of the resulting graph. It should be a framework-specific device object
          (e.g., ``torch.device``). By default, DGL stores the graph on CPU.
  
      Returns
      -------
      DGLGraph
          The created graph.
  
      Notes
      -----
      DGL internally maintains multiple copies of the graph structure in different sparse
      formats and chooses the most efficient one depending on the computation invoked.
      If memory usage becomes an issue in the case of large graphs, use
      :func:`dgl.DGLGraph.formats` to restrict the allowed formats.
  
      Examples
      --------
  
      The following example uses PyTorch backend.
  
      >>> import dgl
      >>> import networkx as nx
      >>> import numpy as np
      >>> import torch
  
      Create a 2-edge NetworkX graph.
  
      >>> nx_g = nx.DiGraph()
      >>> # Add 3 nodes and two features for them
      >>> nx_g.add_nodes_from([0, 1, 2], feat1=np.zeros((3, 1)), feat2=np.ones((3, 1)))
      >>> # Add 2 edges (1, 2) and (2, 1) with two features, one being edge IDs
      >>> nx_g.add_edge(1, 2, weight=np.ones((1, 1)), eid=np.array([1]))
      >>> nx_g.add_edge(2, 1, weight=np.ones((1, 1)), eid=np.array([0]))
  
      Convert it into a DGLGraph with structure only.
  
      >>> g = dgl.from_networkx(nx_g)
  
      Retrieve the node/edge features of the graph.
  
      >>> g = dgl.from_networkx(nx_g, node_attrs=['feat1', 'feat2'], edge_attrs=['weight'])
  
      Use a pre-specified ordering of the edges.
  
      >>> g.edges()
      (tensor([1, 2]), tensor([2, 1]))
      >>> g = dgl.from_networkx(nx_g, edge_id_attr_name='eid')
      (tensor([2, 1]), tensor([1, 2]))
  
      Create a graph on the first GPU with data type int32.
  
      >>> g = dgl.from_networkx(nx_g, idtype=torch.int32, device='cuda:0')
  
      See Also
      --------
      graph
      from_scipy
      """
      # Sanity check
      if (
          edge_id_attr_name is not None
          and edge_id_attr_name
          not in next(iter(nx_graph.edges(data=True)))[-1]
      ):
          raise DGLError(
              "Failed to find the pre-specified edge IDs in the edge features of "
              "the NetworkX graph with name {}".format(
                  edge_id_attr_name
              )
          )
  
      if not nx_graph.is_directed() and not (
          edge_id_attr_name is None and edge_attrs is None
      ):
          raise DGLError(
              "Expect edge_id_attr_name and edge_attrs to be None when nx_graph is "
              "undirected, got {} and {}".format(
                  edge_id_attr_name, edge_attrs
              )
          )
  
      # Relabel nodes using consecutive integers starting from 0
      nx_graph = nx.convert_node_labels_to_integers(
          nx_graph, ordering="sorted"
      )
      if not nx_graph.is_directed():
          nx_graph = nx_graph.to_directed()
  
      (sparse_fmt, arrays), urange, vrange = utils.graphdata2tensors(
          nx_graph, idtype, edge_id_attr_name=edge_id_attr_name
      )
  
      g = create_from_edges(
          sparse_fmt, arrays, "_N", "_E", "_N", urange, vrange
      )
  
      # nx_graph.edges(data=True) returns src, dst, attr_dict
      has_edge_id = (
          nx_graph.number_of_edges() > 0
          and edge_id_attr_name is not None
      )
  
      # handle features
      # copy attributes
      if node_attrs is not None:
          # mapping from feature name to a list of tensors to be concatenated
          attr_dict = defaultdict(list)
          for nid in range(g.num_nodes()):
              for attr in node_attrs:
                  attr_dict[attr].append(nx_graph.nodes[nid][attr])
          for attr in node_attrs:
              g.ndata[attr] = F.copy_to(
                  _batcher(attr_dict[attr]), g.device
              )
  
      if edge_attrs is not None:
          # mapping from feature name to a list of tensors to be concatenated
          attr_dict = defaultdict(lambda: [None] * g.num_edges())
          # each defaultdict value is initialized to be a list of None
          # None here serves as placeholder to be replaced by feature with
          # corresponding edge id
          if has_edge_id:
              num_edges = g.num_edges()
              for _, _, attrs in nx_graph.edges(data=True):
                  if attrs[edge_id_attr_name] >= num_edges:
                      raise DGLError(
                          "Expect the pre-specified edge ids to be"
                          " smaller than the number of edges --"
                          " {}, got {}.".format(num_edges, attrs["id"])
                      )
                  for key in edge_attrs:
                      attr_dict[key][attrs[edge_id_attr_name]] = attrs[
                          key
                      ]
          else:
              # XXX: assuming networkx iteration order is deterministic
              #      so the order is the same as graph_index.from_networkx
              for eid, (_, _, attrs) in enumerate(
                  nx_graph.edges(data=True)
              ):
                  for key in edge_attrs:
                      attr_dict[key][eid] = attrs[key]
          for attr in edge_attrs:
              for val in attr_dict[attr]:
                  if val is None:
                      raise DGLError(
                          "Not all edges have attribute {}.".format(
                              attr
                          )
                      )
              g.edata[attr] = F.copy_to(
                  _batcher(attr_dict[attr]), g.device
              )
  
      return g.to(device)
  
imports: from collections import defaultdict
  from collections.abc import Mapping
  import networkx
  import numpy
  from scipy.sparse import spmatrix
  from .None import backend, graph_index, heterograph_index, utils
  from .base import DGLError, EID, ETYPE, NID, NTYPE
  from .heterograph import combine_frames, DGLBlock, DGLGraph
label_desc: Use image node_id 11 for calling a global function with example usage: from_networkx(nx_graph, node_attrs, edge_attrs, edge_id_attr_name, idtype, device) and returns: g