class_docstr: Neo4jStellarGraph class for graph machine learning on graphs stored in
  a Neo4j database.
  
  This class communicates with Neo4j via a :class:`py2neo.Graph` connected to the graph
  database of interest and contains functions to query the graph data necessary
  for machine learning.
  
  .. seealso:: `Examples using Neoj <https://stellargraph.readthedocs.io/en/stable/demos/connector/neo4j/index.html>`__.
  
  Args:
      graph_db (py2neo.Graph): a :class:`py2neo.Graph` connected to a Neo4j graph database.
      node_label (str, optional): Common label for all nodes in the graph, if such label exists.
          Providing this is useful if there are any indexes created on this label (e.g. on node IDs),
          as it will improve performance of queries.
      id_property (str, optional): Name of Neo4j property to use as ID.
      features_property (str, optional): Name of Neo4j property to use as features.
      is_directed (bool, optional): If True, the data represents a
          directed multigraph, otherwise an undirected multigraph.
class_docstr_tok: ["Neo4jStellarGraph","class","for","graph","machine","learning","on","graphs","stored","in","a","Neo4j","database",".","This","class","communicates","with","Neo4j","via","a",":","class",":","`","py2neo.Graph","`","connected","to","the","graph","database","of","interest","and","contains","functions","to","query","the","graph","data","necessary","for","machine","learning",".","..","seealso",":",":","`","Examples","using","Neoj","<","https",":","\/\/stellargraph.readthedocs.io\/en\/stable\/demos\/connector\/neo4j\/index.html",">","`","__",".","Args",":","graph_db","(","py2neo.Graph",")",":","a",":","class",":","`","py2neo.Graph","`","connected","to","a","Neo4j","graph","database",".","node_label","(","str",",","optional",")",":","Common","label","for","all","nodes","in","the","graph",",","if","such","label","exists",".","Providing","this","is","useful","if","there","are","any","indexes","created","on","this","label","(","e.g",".","on","node","IDs",")",",","as","it","will","improve","performance","of","queries",".","id_property","(","str",",","optional",")",":","Name","of","Neo4j","property","to","use","as","ID",".","features_property","(","str",",","optional",")",":","Name","of","Neo4j","property","to","use","as","features",".","is_directed","(","bool",",","optional",")",":","If","True",",","the","data","represents","a","directed","multigraph",",","otherwise","an","undirected","multigraph","."]
code: def _node_features_from_db(self, nodes):
      return_node = f"""
              WITH {{ID: node.{self.cypher_id_property}, features: node.{self.cypher_features_property}}} AS node_data
              RETURN node_data
              """
      if nodes is None:
          feature_query = f"""
                  {self._match_node()}
                  {return_node}
                  """
          result = self.graph_db.run(feature_query)
          rows = result.data()
          return IndexedArray(
              np.array(
                  [node["node_data"]["features"] for node in rows]
              ),
              index=[node["node_data"]["ID"] for node in rows],
          )
      else:
          if isinstance(nodes, np.ndarray):
              valid = nodes != None
              # we need to create a list with python types to run the neo4j query with
              nodes = [
                  node.item() if node is not None else node
                  for node in nodes
              ]
          elif isinstance(nodes, list):
              valid = np.array(nodes) != None
          else:
              # single node
              valid = np.array([nodes is not None])
              nodes = [nodes]
  
          # None's should be filled with zeros in the feature matrix
          features = np.zeros(
              (len(nodes), self.node_feature_sizes()[self._node_type])
          )
  
          # fill valid locs with features
          feature_query = f"""
                  UNWIND $node_id_list AS node_id
                  {self._match_node()} WHERE node.{self.cypher_id_property} = node_id
                  {return_node}
                  """
          result = self.graph_db.run(
              feature_query, parameters={"node_id_list": nodes}
          )
          rows = result.data()
  
          # this method currently doesn't handle any other invalid IDs. If there are other
          # invalid ids, we should raise an error
          if len(rows) != sum(valid):
              ids = {node["node_data"]["ID"] for node in rows}
              invalid = [
                  node
                  for node in nodes
                  if node is not None and node not in ids
              ]
              raise ValueError(
                  f"nodes: Found values that did not return any results from the database: {comma_sep(invalid)}"
              )
  
          features[valid, :] = [
              row["node_data"]["features"] for row in rows
          ]
  
          return IndexedArray(features, index=nodes)
  
imports: import numpy
  import scipy.sparse
  import pandas
  import re
  import warnings
  from ...None import globalvar
  from ...core.experimental import experimental
  from ...core import convert
  from ...core.indexed_array import IndexedArray
  from ...core.graph import extract_element_features
  from ...core.validation import comma_sep
label_desc: Use image node_id 5 for calling the Neo4jStellarGraph obj's underlying member method code with example usage: obj._node_features_from_db(nodes) and returns: IndexedArray, IndexedArray