class_docstr: Class which stores vertex and edge properties that can be used to construct
  Graphs from individual property selections and used later to annotate graph
  algorithm results with corresponding properties.
class_docstr_tok: ["Class","which","stores","vertex","and","edge","properties","that","can","be","used","to","construct","Graphs","from","individual","property","selections","and","used","later","to","annotate","graph","algorithm","results","with","corresponding","properties","."]
docstr: Add properties to df that represent the vertices and edges in graph G.
  
  Parameters
  ----------
  df : cudf.DataFrame or pandas.DataFrame
      A DataFrame containing edges identified by edge_vertex_col_names
      which will have properties for those edges added to it.
  G : cugraph.Graph (or subclass of) instance.
      Graph containing the edges specified in df. The Graph instance must
      have been generated from a prior call to extract_subgraph() in
      order to have the edge meta-data used to look up the correct
      properties.
  edge_vertex_col_names : tuple of strings
      The column names in df that represent the source and destination
      vertices, used for identifying edges.
  
  Returns
  -------
  A copy of df with additional columns corresponding to properties for
  the edge in the row.
  
  Examples
  --------
  >>> import cudf
  >>> from cugraph.experimental import PropertyGraph
  >>> df = cudf.DataFrame(columns=["src", "dst", "some_property"],
  ...                      data=[(99, 22, "a"),
  ...                            (98, 34, "b"),
  ...                            (97, 56, "c"),
  ...                            (96, 88, "d"),
  ...                           ])
  >>> pG = PropertyGraph()
  >>> pG.add_edge_data(df, type_name="etype", vertex_col_names=("src", "dst"))
  >>> G = pG.extract_subgraph(create_using=cugraph.Graph(directed=True))
  >>> # Represents results of an algorithm run on the graph returning a dataframe
  >>> algo_result = cudf.DataFrame({"from":df.src,
  ...                                "to":df.dst,
  ...                                "result": range(len(df.src))})
  >>> algo_result2 = pG.annotate_dataframe(algo_result,
  ...                                       G,
  ...                                       edge_vertex_col_names=("from", "to"))
  >>> print (algo_result2.sort_index(axis=1))
  _EDGE_ID_ _TYPE_  from  result some_property  to
  0          0  etype    99       0             a  22
  1          1  etype    98       1             b  34
  2          2  etype    97       2             c  56
  3          3  etype    96       3             d  88
code: def annotate_dataframe(self, df, G, edge_vertex_col_names):
      """
      Add properties to df that represent the vertices and edges in graph G.
  
      Parameters
      ----------
      df : cudf.DataFrame or pandas.DataFrame
          A DataFrame containing edges identified by edge_vertex_col_names
          which will have properties for those edges added to it.
      G : cugraph.Graph (or subclass of) instance.
          Graph containing the edges specified in df. The Graph instance must
          have been generated from a prior call to extract_subgraph() in
          order to have the edge meta-data used to look up the correct
          properties.
      edge_vertex_col_names : tuple of strings
          The column names in df that represent the source and destination
          vertices, used for identifying edges.
  
      Returns
      -------
      A copy of df with additional columns corresponding to properties for
      the edge in the row.
  
      Examples
      --------
      >>> import cudf
      >>> from cugraph.experimental import PropertyGraph
      >>> df = cudf.DataFrame(columns=["src", "dst", "some_property"],
      ...                      data=[(99, 22, "a"),
      ...                            (98, 34, "b"),
      ...                            (97, 56, "c"),
      ...                            (96, 88, "d"),
      ...                           ])
      >>> pG = PropertyGraph()
      >>> pG.add_edge_data(df, type_name="etype", vertex_col_names=("src", "dst"))
      >>> G = pG.extract_subgraph(create_using=cugraph.Graph(directed=True))
      >>> # Represents results of an algorithm run on the graph returning a dataframe
      >>> algo_result = cudf.DataFrame({"from":df.src,
      ...                                "to":df.dst,
      ...                                "result": range(len(df.src))})
      >>> algo_result2 = pG.annotate_dataframe(algo_result,
      ...                                       G,
      ...                                       edge_vertex_col_names=("from", "to"))
      >>> print (algo_result2.sort_index(axis=1))
      _EDGE_ID_ _TYPE_  from  result some_property  to
      0          0  etype    99       0             a  22
      1          1  etype    98       1             b  34
      2          2  etype    97       2             c  56
      3          3  etype    96       3             d  88
      """
      # FIXME: check all args
      # FIXME: also provide the ability to annotate vertex data.
      (src_col_name, dst_col_name) = edge_vertex_col_names
  
      df_type = type(df)
      if df_type is not self.__dataframe_type:
          raise TypeError(
              f"df type {df_type} does not match DataFrame type "
              f"{self.__dataframe_type} used in PropertyGraph"
          )
  
      if hasattr(G, "edge_data"):
          edge_info_df = G.edge_data
      else:
          raise AttributeError(
              "Graph G does not have attribute 'edge_data'"
          )
  
      # Join on shared columns and the indices
      cols = self.__edge_prop_dataframe.columns.intersection(
          edge_info_df.columns
      ).to_list()
      cols.append(self.edge_id_col_name)
  
      # New result includes only properties from the src/dst edges identified
      # by edge IDs. All other data in df is merged based on src/dst values.
      # NOTE: results from MultiGraph graphs will have to include edge IDs!
      edge_props_df = edge_info_df.merge(
          self.__edge_prop_dataframe, on=cols, how="inner"
      )
  
      # FIXME: also allow edge ID col to be passed in and renamed.
      new_df = df.rename(
          columns={
              src_col_name: self.src_col_name,
              dst_col_name: self.dst_col_name,
          }
      )
      new_df = new_df.merge(edge_props_df)
      # restore the original src/dst column names
      new_df.rename(
          columns={
              self.src_col_name: src_col_name,
              self.dst_col_name: dst_col_name,
          },
          inplace=True,
      )
  
      # restore the original dtypes
      new_df = self.__update_dataframe_dtypes(
          new_df, self.__edge_prop_dtypes
      )
      for col in df.columns:
          new_df[col] = new_df[col].astype(df.dtypes[col])
  
      # FIXME: consider removing internal columns (_EDGE_ID_, etc.) and
      # columns from edge types not included in the edges in df.
      return new_df
  
imports: import cudf
  import numpy
  import cugraph
  from cugraph.utilities.utils import import_optional, MissingModule, create_list_series_from_2d_ar
  from typing import Union
label_desc: Use image node_id 28 for calling the EXPERIMENTAL__PropertyGraph obj's underlying member method code with example usage: obj.annotate_dataframe(df, G, edge_vertex_col_names) and returns: new_df