code: def from_scipy_sparse_array(
      A,
      parallel_edges=False,
      create_using=None,
      edge_attribute="weight",
  ):
      """Creates a new graph from an adjacency matrix given as a SciPy sparse
      array.
  
      Parameters
      ----------
      A: scipy.sparse array
        An adjacency matrix representation of a graph
  
      parallel_edges : Boolean
        If this is True, `create_using` is a multigraph, and `A` is an
        integer matrix, then entry *(i, j)* in the matrix is interpreted as the
        number of parallel edges joining vertices *i* and *j* in the graph.
        If it is False, then the entries in the matrix are interpreted as
        the weight of a single edge joining the vertices.
  
      create_using : NetworkX graph constructor, optional (default=nx.Graph)
         Graph type to create. If graph instance, then cleared before populated.
  
      edge_attribute: string
         Name of edge attribute to store matrix numeric value. The data will
         have the same type as the matrix entry (int, float, (real,imag)).
  
      Notes
      -----
      For directed graphs, explicitly mention create_using=nx.DiGraph,
      and entry i,j of A corresponds to an edge from i to j.
  
      If `create_using` is :class:`networkx.MultiGraph` or
      :class:`networkx.MultiDiGraph`, `parallel_edges` is True, and the
      entries of `A` are of type :class:`int`, then this function returns a
      multigraph (constructed from `create_using`) with parallel edges.
      In this case, `edge_attribute` will be ignored.
  
      If `create_using` indicates an undirected multigraph, then only the edges
      indicated by the upper triangle of the matrix `A` will be added to the
      graph.
  
      Examples
      --------
      >>> import scipy as sp
      >>> A = sp.sparse.eye(2, 2, 1)
      >>> G = nx.from_scipy_sparse_array(A)
  
      If `create_using` indicates a multigraph and the matrix has only integer
      entries and `parallel_edges` is False, then the entries will be treated
      as weights for edges joining the nodes (without creating parallel edges):
  
      >>> A = sp.sparse.csr_array([[1, 1], [1, 2]])
      >>> G = nx.from_scipy_sparse_array(A, create_using=nx.MultiGraph)
      >>> G[1][1]
      AtlasView({0: {'weight': 2}})
  
      If `create_using` indicates a multigraph and the matrix has only integer
      entries and `parallel_edges` is True, then the entries will be treated
      as the number of parallel edges joining those two vertices:
  
      >>> A = sp.sparse.csr_array([[1, 1], [1, 2]])
      >>> G = nx.from_scipy_sparse_array(
      ...     A, parallel_edges=True, create_using=nx.MultiGraph
      ... )
      >>> G[1][1]
      AtlasView({0: {'weight': 1}, 1: {'weight': 1}})
  
      """
      G = nx.empty_graph(0, create_using)
      n, m = A.shape
      if n != m:
          raise nx.NetworkXError(
              f"Adjacency matrix not square: nx,ny={A.shape}"
          )
      # Make sure we get even the isolated nodes of the graph.
      G.add_nodes_from(range(n))
      # Create an iterable over (u, v, w) triples and for each triple, add an
      # edge from u to v with weight w.
      triples = _generate_weighted_edges(A)
      # If the entries in the adjacency matrix are integers, the graph is a
      # multigraph, and parallel_edges is True, then create parallel edges, each
      # with weight 1, for each entry in the adjacency matrix. Otherwise, create
      # one edge for each positive entry in the adjacency matrix and set the
      # weight of that edge to be the entry in the matrix.
      if (
          A.dtype.kind in ("i", "u")
          and G.is_multigraph()
          and parallel_edges
      ):
          chain = itertools.chain.from_iterable
          # The following line is equivalent to:
          #
          #     for (u, v) in edges:
          #         for d in range(A[u, v]):
          #             G.add_edge(u, v, weight=1)
          #
          triples = chain(
              ((u, v, 1) for d in range(w)) for (u, v, w) in triples
          )
      # If we are creating an undirected multigraph, only add the edges from the
      # upper triangle of the matrix. Otherwise, add all the edges. This relies
      # on the fact that the vertices created in the
      # `_generated_weighted_edges()` function are actually the row/column
      # indices for the matrix `A`.
      #
      # Without this check, we run into a problem where each edge is added twice
      # when `G.add_weighted_edges_from()` is invoked below.
      if G.is_multigraph() and not G.is_directed():
          triples = ((u, v, d) for u, v, d in triples if u <= v)
      G.add_weighted_edges_from(triples, weight=edge_attribute)
      return G
  
file_path: networkx/networkx/convert_matrix.py
imports: import itertools
  from collections import defaultdict
  import networkx
  from networkx.utils import not_implemented_for
label_desc: Use image node_id 11 for calling a global function with example usage: from_scipy_sparse_array(A, parallel_edges, create_using, edge_attribute) and returns: G