code: def from_igraph(
      self,
      ig,
      node_attributes: Optional[List[str]] = None,
      edge_attributes: Optional[List[str]] = None,
      load_nodes: bool = True,
      load_edges: bool = True,
      merge_if_existing: bool = True,
  ) -> Plottable:
      """
      Convert igraph object into Plotter
  
      If base g has _node, _source, _destination definitions, use them
  
      When merge_if_existing with preexisting nodes/edges df and shapes match ig, combine attributes
  
      For merge_if_existing to work with edges, must set g._edge and have corresponding edge index attribute in igraph.Graph
  
      :param ig: Source igraph object
      :type ig: igraph
  
      :param node_attributes: Subset of node attributes to load; None means all (default)
      :type node_attributes: Optional[List[str]]
  
      :param edge_attributes: Subset of edge attributes to load; None means all (default)
      :type edge_attributes: Optional[List[str]]
  
      :param load_nodes: Whether to load nodes dataframe (default True)
      :type load_nodes: bool
  
      :param load_edges: Whether to load edges dataframe (default True)
      :type load_edges: bool
  
      :param merge_if_existing: Whether to merge with existing node/edge dataframes (default True)
      :param merge_if_existing: bool
  
      :returns: Plotter
  
      **Example: Convert from igraph, including all node/edge properties**
          ::
  
              import graphistry, pandas as pd
              edges = pd.DataFrame({'s': ['a', 'b', 'c', 'd'], 'd': ['b', 'c', 'd', 'e'], 'v': [101, 102, 103, 104]})
              g = graphistry.edges(edges, 's', 'd').materialize_nodes().get_degrees()
              assert 'degree' in g._nodes.columns
              g2 = g.from_igraph(g.to_igraph())
              assert len(g2._nodes.columns) == len(g._nodes.columns)
  
      **Example: Enrich from igraph, but only load in 1 node attribute**
          ::
  
              import graphistry, pandas as pd
              edges = pd.DataFrame({'s': ['a', 'b', 'c', 'd'], 'd': ['b', 'c', 'd', 'e'], 'v': [101, 102, 103, 104]})
              g = graphistry.edges(edges, 's', 'd').materialize_nodes().get_degree()
              assert 'degree' in g._nodes
              ig = g.to_igraph(include_nodes=False)
              assert 'degree' not in ig.vs
              ig.vs['pagerank'] = ig.pagerank()
              g2 = g.from_igraph(ig, load_edges=False, node_attributes=[g._node, 'pagerank'])
              assert 'pagerank' in g2._nodes
              asssert 'degree' in g2._nodes
  
      """
  
      g = self.bind()
  
      # Compute nodes: need indexing for edges
  
      node_col = g._node or NODE
  
      ig_vs_df = ig.get_vertex_dataframe()
      nodes_df = ig_vs_df
  
      if load_nodes:
          if node_col not in nodes_df:
              # TODO if no g._nodes but 'name' in nodes_df, still use?
              if (
                  ("name" in nodes_df)
                  and (  # noqa: W504
                      g._nodes is not None and g._node is not None
                  )
                  and (  # noqa: W504
                      g._nodes[g._node].dtype.name
                      == nodes_df["name"].dtype.name
                  )
              ):
                  nodes_df = nodes_df.rename(columns={"name": node_col})
              elif ("name" in nodes_df) and (g._nodes is None):
                  nodes_df = nodes_df.rename(columns={"name": node_col})
              else:
                  nodes_df = nodes_df.reset_index().rename(
                      columns={nodes_df.index.name: node_col}
                  )
  
          if node_attributes is not None:
              nodes_df = nodes_df[node_attributes]
  
          if g._nodes is not None and merge_if_existing:
              if g._node is None:
                  raise ValueError(
                      "Non-None g._nodes and merge_if_existing=True, yet no g._node is defined"
                  )
              if len(g._nodes) != len(nodes_df):
                  logger.warning(
                      "node tables do not match in length; switch merge_if_existing to False or load_nodes to False or add missing nodes"
                  )
  
              g_nodes_trimmed = g._nodes[
                  [
                      x
                      for x in g._nodes
                      if x not in nodes_df or x == g._node
                  ]
              ]
              nodes_df = nodes_df.merge(
                  g_nodes_trimmed, how="left", on=g._node
              )
  
          nodes_df = nodes_df.reset_index(drop=True)
          g = g.nodes(nodes_df, node_col)
  
      # #####
  
      if load_edges:
          # #####
  
          # TODO: Reuse for g.nodes(nodes_df) as well?
  
          if len(ig_vs_df.columns) == 0:
              node_id_col = None
          elif node_col in ig_vs_df:
              node_id_col = node_col
          # User to_igraph() with numeric IDs may swizzle id mappings (ex: sparse numeric) so try to un-swizzle
          # FIXME: how to handle dense edge case's swizzling?
          elif (
              g._node is not None
              and g._nodes[g._node].dtype.name
              == ig_vs_df.reset_index()["vertex ID"].dtype.name
          ):
              found = False
              # FIXME: This seems quite error prone... what if any fields already exist?
              for c in ["name", "id", "idx", NODE]:
                  if c in ig_vs_df.columns:
                      if (
                          g._nodes[g._node].min() == ig_vs_df[c].min()
                          and g._nodes[g._node].max()
                          == ig_vs_df[c].max()
                      ):
                          if (
                              g._nodes[g._node]
                              .sort_values()
                              .equals(ig_vs_df[c].sort_values())
                          ):
                              node_id_col = c
                              found = True
                              break
              if not found:
                  logger.debug(
                      "lacks matching sortable dimension, likely passed integers-as-vids, continue without remapping"
                  )
                  node_id_col = None
          elif "name" in ig_vs_df:
              node_id_col = "name"
          else:
              raise ValueError(
                  "Could not determine graphistry node ID column to match igraph nodes on"
              )
  
          if node_id_col is None:
              ig_index_to_node_id_df = None
          else:
              ig_index_to_node_id_df = (
                  ig_vs_df[[node_id_col]]
                  .reset_index()
                  .rename(columns={"vertex ID": "ig_index"})
              )
  
          # #####
  
          src_col = g._source or SRC_IGRAPH
          dst_col = g._destination or DST_IGRAPH
          edges_df = ig.get_edge_dataframe()
  
          if ig_index_to_node_id_df is not None:
              edges_df["source"] = edges_df[["source"]].merge(
                  ig_index_to_node_id_df.rename(
                      columns={"ig_index": "source"}
                  ),
                  how="left",
                  on="source",
              )[node_id_col]
              edges_df["target"] = edges_df[["target"]].merge(
                  ig_index_to_node_id_df.rename(
                      columns={"ig_index": "target"}
                  ),
                  how="left",
                  on="target",
              )[node_id_col]
  
          edges_df = edges_df.rename(
              columns={"source": src_col, "target": dst_col}
          )
  
          if edge_attributes is not None:
              edges_df = edges_df[edge_attributes]
  
          if g._edges is not None and merge_if_existing:
              g_indexed = g
  
              if g._edge is None:
                  g_indexed = g.edges(
                      g._edges.reset_index().rename(
                          columns={
                              g._edges.index.name
                              or "index": "__edge_index__"
                          }
                      ),
                      g._source,
                      g._destination,
                      "__edge_index__",
                  )
                  logger.warning(
                      "edge index g._edge not set so using edge index as ID; set g._edge via g.edges(), or change merge_if_existing to False"
                  )
  
              if g_indexed._edge not in edges_df:
                  logger.warning(
                      "edge index g._edge %s missing as attribute in ig; using ig edge order for IDs",
                      g_indexed._edge,
                  )
                  edges_df = edges_df.reset_index().rename(
                      columns={
                          edges_df.index.name
                          or "index": g_indexed._edge
                      }
                  )
  
              if len(g_indexed._edges.columns) == 3 and (
                  len(g_indexed._edges) == len(edges_df)
              ):
                  # opt: skip merge: no old columns
                  1
              elif (
                  (len(edges_df.columns) == 3)
                  or len(edges_df.columns) == 0
              ) and (len(g._edges) == len(edges_df)):
                  # opt: skip merge: no new columns
                  edges_df = g._edges
              else:
                  if len(g._edges) != len(edges_df):
                      logger.warning(
                          "edge tables do not match in length; switch merge_if_existing to False or load_edges to False or add missing edges"
                      )
                  g_edges_trimmed = g_indexed._edges[
                      [
                          x
                          for x in g_indexed._edges
                          if x not in edges_df or x == g_indexed._edge
                      ]
                  ]
                  edges_df = edges_df.merge(
                      g_edges_trimmed, how="left", on=g_indexed._edge
                  )
  
              if g._edge is None:
                  edges_df = edges_df[
                      [x for x in edges_df if x != g_indexed._edge]
                  ]
  
          g = g.edges(edges_df, src_col, dst_col)
  
      return g
  
file_path: pygraphistry/graphistry/plugins/igraph.py
imports: import pandas
  from typing import Any, List, Optional
  from graphistry.constants import NODE
  from graphistry.Plottable import Plottable
  from graphistry.util import setup_logger
label_desc: Use image node_id 1 for calling a global function with example usage: from_igraph(ig, node_attributes, edge_attributes, load_nodes, load_edges, merge_if_existing) and returns: g