code: def _construct_graph_from_dataframe(
      cls,
      edges,
      directed: bool = True,
      vertices=None,
      use_vids: bool = True,
  ):
      """Generates a graph from one or two dataframes.
  
      @param edges: pandas DataFrame containing edges and metadata. The first
        two columns of this DataFrame contain the source and target vertices
        for each edge. These indicate the vertex IDs as nonnegative integers
        rather than vertex names unless C{use_vids} is False. Further columns
        may contain edge attributes.
      @param directed: whether the graph is directed
      @param vertices: None (default) or pandas DataFrame containing vertex
        metadata. The DataFrame's index must contain the vertex IDs as a
        sequence of intergers from 0 to C{len(vertices) - 1}. If C{use_vids}
        is C{False}, the first column must contain the unique vertex names.
        Vertex names should be strings for full compatibility, but many functions
        will work if you set the name with any hashable object. All other columns
        will be added as vertex attributes by column name.
      @param use_vids: whether to interpret the first two columns of the C{edges}
        argument as vertex ids (0-based integers) instead of vertex names.
        If this argument is set to True and the first two columns of C{edges}
        are not integers, an error is thrown.
  
      @return: the graph
  
      Vertex names in either the C{edges} or C{vertices} arguments that are set
      to NaN (not a number) will be set to the string "NA". That might lead
      to unexpected behaviour: fill your NaNs with values before calling this
      function to mitigate.
      """
      try:
          import pandas as pd
      except ImportError:
          raise ImportError(
              "You should install pandas in order to use this function"
          ) from None
  
      if edges.shape[1] < 2:
          raise ValueError(
              "The 'edges' DataFrame must contain at least two columns"
          )
      if vertices is not None and vertices.shape[1] < 1:
          raise ValueError(
              "The 'vertices' DataFrame must contain at least one column"
          )
  
      if use_vids:
          if str(edges.dtypes.iloc[0]).startswith(
              ("int", "Int")
          ) and str(edges.dtypes.iloc[1]).startswith(("int", "Int")):
              # Check pandas nullable integer data type:
              # https://pandas.pydata.org/docs/user_guide/integer_na.html
              if (edges.iloc[:, :2].isna()).any(axis=None):
                  raise ValueError(
                      "Source and target IDs must not be null"
                  )
  
              if (edges.iloc[:, :2] < 0).any(axis=None):
                  raise ValueError(
                      "Source and target IDs must not be negative"
                  )
          else:
              raise TypeError(
                  f"Source and target IDs must be 0-based integers, found types {edges.dtypes.tolist()[:2]}"
              )
  
          if vertices is not None:
              vertices = vertices.sort_index()
              if not vertices.index.equals(
                  pd.RangeIndex.from_range(range(vertices.shape[0]))
              ):
                  if not str(vertices.index.dtype).startswith("int"):
                      raise TypeError(
                          f"Vertex IDs must be 0-based integers, found type {vertices.index.dtype}"
                      )
                  elif (vertices.index < 0).any(axis=None):
                      raise ValueError(
                          "Vertex IDs must not be negative"
                      )
                  else:
                      raise ValueError(
                          f"Vertex IDs must be an integer sequence from 0 to {vertices.shape[0] - 1}"
                      )
      else:
          # Handle if some source and target names in 'edges' are 'NA'
          if edges.iloc[:, :2].isna().any(axis=None):
              warn(
                  "In the first two columns of 'edges' NA elements were replaced with string \"NA\"",
                  stacklevel=1,
              )
              edges = edges.copy()
              edges.iloc[:, :2].fillna("NA", inplace=True)
  
          # Bring DataFrame(s) into same format as with 'use_vids=True'
          if vertices is None:
              vertices = pd.DataFrame(
                  {"name": pd.unique(edges.values[:, :2].ravel())}
              )
  
          if vertices.iloc[:, 0].isna().any():
              warn(
                  "In the first column of 'vertices' NA elements were replaced with string \"NA\"",
                  stacklevel=1,
              )
              vertices = vertices.copy()
              vertices.iloc[:, 0].fillna("NA", inplace=True)
  
          if vertices.iloc[:, 0].duplicated().any():
              raise ValueError("Vertex names must be unique")
  
          if vertices.shape[1] > 1 and "name" in vertices.columns[1:]:
              raise ValueError(
                  "Vertex attribute conflict: DataFrame already contains column 'name'"
              )
  
          vertices = vertices.rename(
              {vertices.columns[0]: "name"}, axis=1
          ).reset_index(drop=True)
  
          # Map source and target names in 'edges' to IDs
          vid_map = pd.Series(vertices.index, index=vertices.iloc[:, 0])
          edges = edges.copy()
          edges[edges.columns[0]] = edges.iloc[:, 0].map(vid_map)
          edges[edges.columns[1]] = edges.iloc[:, 1].map(vid_map)
  
      # Create graph
      if vertices is None:
          nv = edges.iloc[:, :2].max().max() + 1
          g = cls(n=nv, directed=directed)
      else:
          if not edges.iloc[:, :2].isin(vertices.index).all(axis=None):
              raise ValueError(
                  "Some vertices in the edge DataFrame are missing from vertices DataFrame"
              )
          nv = vertices.shape[0]
          g = cls(n=nv, directed=directed)
          # Add vertex attributes
          for col in vertices.columns:
              g.vs[col] = vertices[col].tolist()
  
      # add edges including optional attributes
      e_list = list(
          edges.iloc[:, :2].itertuples(index=False, name=None)
      )
      e_attr = (
          edges.iloc[:, 2:].to_dict(orient="list")
          if edges.shape[1] > 2
          else None
      )
      g.add_edges(e_list, e_attr)
  
      return g
  
file_path: python-igraph/src/igraph/io/objects.py
imports: from typing import Union, Sequence
  from collections import defaultdict
  from itertools import repeat
  from warnings import warn
  from igraph.datatypes import UniqueIdGenerator
label_desc: Use image node_id 5 for calling a global function with example usage: _construct_graph_from_dataframe(cls, edges, directed, vertices, use_vids) and returns: g