docstr: Input a natural language query and return a graph of results.
      See help(g.search) for more information
  
  Args:
      :query (str): query input eg "coding best practices"
      :scale (float, optional): edge weigh threshold,  Defaults to 0.5.
      :top_n (int, optional): how many results to return. Defaults to 100.
      :thresh (float, optional): distance threshold from query vector to returned results.
                                  Defaults to 5000, set large just in case,
                                  but could be as low as 10.
      :broader (bool, optional): if True, will retrieve entities connected via an edge
          that were not necessarily bubbled up in the results_dataframe. Defaults to False.
      :inplace (bool, optional): whether to return new instance (default) or mutate self.
                                  Defaults to False.
  
  Returns:
      graphistry Instance: g
docstr_tok: ["Input","a","natural","language","query","and","return","a","graph","of","results",".","See","help","(","g.search",")","for","more","information","Args",":",":","query","(","str",")",":","query","input","eg","``","coding","best","practices","''",":","scale","(","float",",","optional",")",":","edge","weigh","threshold",",","Defaults","to","0.5.",":","top_n","(","int",",","optional",")",":","how","many","results","to","return",".","Defaults","to","100.",":","thresh","(","float",",","optional",")",":","distance","threshold","from","query","vector","to","returned","results",".","Defaults","to","5000",",","set","large","just","in","case",",","but","could","be","as","low","as","10.",":","broader","(","bool",",","optional",")",":","if","True",",","will","retrieve","entities","connected","via","an","edge","that","were","not","necessarily","bubbled","up","in","the","results_dataframe",".","Defaults","to","False",".",":","inplace","(","bool",",","optional",")",":","whether","to","return","new","instance","(","default",")","or","mutate","self",".","Defaults","to","False",".","Returns",":","graphistry","Instance",":","g"]
code: def search_graph(
      self,
      query: str,
      scale: float = 0.5,
      top_n: int = 100,
      thresh: float = 5000,
      broader: bool = False,
      inplace: bool = False,
  ):
      """Input a natural language query and return a graph of results.
          See help(g.search) for more information
  
      Args:
          :query (str): query input eg "coding best practices"
          :scale (float, optional): edge weigh threshold,  Defaults to 0.5.
          :top_n (int, optional): how many results to return. Defaults to 100.
          :thresh (float, optional): distance threshold from query vector to returned results.
                                      Defaults to 5000, set large just in case,
                                      but could be as low as 10.
          :broader (bool, optional): if True, will retrieve entities connected via an edge
              that were not necessarily bubbled up in the results_dataframe. Defaults to False.
          :inplace (bool, optional): whether to return new instance (default) or mutate self.
                                      Defaults to False.
  
      Returns:
          graphistry Instance: g
      """
      if inplace:
          res = self
      else:
          res = self.bind()
  
      edf = edges = res._edges
      # print('shape of edges', edf.shape)
      rdf = df = res._nodes
      # print('shape of nodes', rdf.shape)
      node = res._node
      indices = rdf[node]
      src = res._source
      dst = res._destination
      if query != "":
          # run a real query, else return entire graph
          rdf, _ = res.search(
              query, thresh=thresh, fuzzy=True, top_n=top_n
          )
          if not rdf.empty:
              indices = rdf[node]
              # now get edges from indices
              if (
                  broader
              ):  # this will make a broader graph, finding NN in src OR dst
                  edges = edf[
                      (edf[src].isin(indices))
                      | (edf[dst].isin(indices))
                  ]
              else:  # finds only edges between results from query, if they exist,
                  # default smaller graph
                  edges = edf[
                      (edf[src].isin(indices))
                      & (edf[dst].isin(indices))
                  ]
          else:
              logger.warn(
                  "**No results found due to empty DataFrame, returning original graph"
              )
              return res
  
      try:  # for umap'd edges
          edges = edges.query(f"{WEIGHT} > {scale}")
      except:  # for explicit edges
          pass
  
      found_indices = pd.concat(
          [edges[src], edges[dst], indices], axis=0
      ).unique()
      emb = None
      try:
          tdf = rdf.iloc[found_indices]
          feats = res._node_features.iloc[found_indices]  # type: ignore
          if res._umap is not None:
              emb = res._node_embedding.iloc[found_indices]  # type: ignore
      except Exception:  # for explicit relabeled nodes
          # logger.exception(e)
          tdf = rdf[df[node].isin(found_indices)]
          feats = res._node_features.loc[tdf.index]  # type: ignore
          if res._umap is not None:
              emb = res._node_embedding[df[node].isin(found_indices)]  # type: ignore
      logger.info(
          f" - Returning edge dataframe of size {edges.shape[0]}"
      )
      # get all the unique nodes
      logger.info(
          f" - Returning {tdf.shape[0]} unique nodes given scale {scale} and thresh {thresh}"
      )
  
      g = res.edges(edges, src, dst).nodes(tdf, node)
      # add them back so they sync with .dbscan etc calls
      g._node_features = feats
      g._node_embedding = emb
  
      if g._name is not None:
          name = f"{g._name}-query:{query}"
      else:
          name = f"query:{query}"
      g = g.name(name)  # type: ignore
      return g
  
file_path: pygraphistry/graphistry/text_utils.py
imports: import pandas
  from .feature_utils import FeatureMixin
  from .ai_utils import search_to_df, FaissVectorSearch
  from .constants import WEIGHT, DISTANCE
  from logging import getLogger
  from typing import TYPE_CHECKING
label_desc: Use image node_id 8 for calling the SearchToGraphMixin obj's underlying member method code with example usage: obj.search_graph(query, scale, top_n, thresh, broader, inplace) and returns: g, res