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 a dataframe describing vertex properties to the PropertyGraph.
  Can contain additional vertices that will not have associated edges.
  
  Parameters
  ----------
  dataframe : DataFrame-compatible instance
      A DataFrame instance with a compatible Pandas-like DataFrame
      interface.
  vertex_col_name : string
      The column name that contains the values to be used as vertex IDs,
      or the name of the index if the index is vertex IDs.
      Specifying the index may be more efficient.
  type_name : string, optional
      The name to be assigned to the type of property being added. For
      example, if dataframe contains data about users, type_name might be
      "users". If not specified, the type of properties will be added as
      the empty string, "".
  property_columns : list of strings, optional
      List of column names in dataframe to be added as properties. All
      other columns in the dataframe will be ignored. If not specified, all
      columns in dataframe are added.
  vector_properties : dict of string to list of strings, optional
      A dict of vector properties to create from columns in the dataframe.
      Each vector property stores an array for each vertex.
      The dict keys are the new vector property names, and the dict values
      should be Python lists of column names from which to create the vector
      property. Columns used to create vector properties won't be added to
      the property graph by default, but may be included as properties by
      including them in the property_columns argument.
      Use ``PropertyGraph.vertex_vector_property_to_array`` to convert a
      vertex vector property to an array.
  vector_property : string, optional
      If provided, all columns not included in other arguments will be used
      to create a vector property with the given name. This is often used
      for convenience instead of ``vector_properties`` when all input
      properties should be converted to a vector property.
  
  Returns
  -------
  None
  
  Examples
  --------
  >>> import cugraph
  >>> 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"))
  >>> vert_df = cudf.DataFrame({"vert_id": [99, 22, 98, 34, 97, 56, 96, 88],
  ...                           "v_prop": [1, 2, 3, 4, 5, 6, 7, 8]})
  >>> pG.add_vertex_data(vert_df, type_name="vtype", vertex_col_name="vert_id")
  >>> pG.get_vertex_data().sort_index(axis=1)
  _TYPE_  _VERTEX_  v_prop
  0  vtype        99       1
  1  vtype        22       2
  2  vtype        98       3
  3  vtype        34       4
  4  vtype        97       5
  5  vtype        56       6
  6  vtype        96       7
  7  vtype        88       8
code: def add_vertex_data(
      self,
      dataframe,
      vertex_col_name,
      type_name=None,
      property_columns=None,
      vector_properties=None,
      vector_property=None,
  ):
      """
      Add a dataframe describing vertex properties to the PropertyGraph.
      Can contain additional vertices that will not have associated edges.
  
      Parameters
      ----------
      dataframe : DataFrame-compatible instance
          A DataFrame instance with a compatible Pandas-like DataFrame
          interface.
      vertex_col_name : string
          The column name that contains the values to be used as vertex IDs,
          or the name of the index if the index is vertex IDs.
          Specifying the index may be more efficient.
      type_name : string, optional
          The name to be assigned to the type of property being added. For
          example, if dataframe contains data about users, type_name might be
          "users". If not specified, the type of properties will be added as
          the empty string, "".
      property_columns : list of strings, optional
          List of column names in dataframe to be added as properties. All
          other columns in the dataframe will be ignored. If not specified, all
          columns in dataframe are added.
      vector_properties : dict of string to list of strings, optional
          A dict of vector properties to create from columns in the dataframe.
          Each vector property stores an array for each vertex.
          The dict keys are the new vector property names, and the dict values
          should be Python lists of column names from which to create the vector
          property. Columns used to create vector properties won't be added to
          the property graph by default, but may be included as properties by
          including them in the property_columns argument.
          Use ``PropertyGraph.vertex_vector_property_to_array`` to convert a
          vertex vector property to an array.
      vector_property : string, optional
          If provided, all columns not included in other arguments will be used
          to create a vector property with the given name. This is often used
          for convenience instead of ``vector_properties`` when all input
          properties should be converted to a vector property.
  
      Returns
      -------
      None
  
      Examples
      --------
      >>> import cugraph
      >>> 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"))
      >>> vert_df = cudf.DataFrame({"vert_id": [99, 22, 98, 34, 97, 56, 96, 88],
      ...                           "v_prop": [1, 2, 3, 4, 5, 6, 7, 8]})
      >>> pG.add_vertex_data(vert_df, type_name="vtype", vertex_col_name="vert_id")
      >>> pG.get_vertex_data().sort_index(axis=1)
      _TYPE_  _VERTEX_  v_prop
      0  vtype        99       1
      1  vtype        22       2
      2  vtype        98       3
      3  vtype        34       4
      4  vtype        97       5
      5  vtype        56       6
      6  vtype        96       7
      7  vtype        88       8
      """
      if type(dataframe) not in _dataframe_types:
          raise TypeError(
              "dataframe must be one of the following types: "
              f"{_dataframe_types}, got: {type(dataframe)}"
          )
      if vertex_col_name not in dataframe.columns:
          if vertex_col_name != dataframe.index.name:
              raise ValueError(
                  f"{vertex_col_name} is not a column in "
                  f"dataframe: {dataframe.columns}"
              )
          index_is_set = True
      else:
          index_is_set = False
      if type_name is not None and not isinstance(type_name, str):
          raise TypeError(
              f"type_name must be a string, got: {type(type_name)}"
          )
      if type_name is None:
          type_name = self._default_type_name
      if property_columns:
          if type(property_columns) is not list:
              raise TypeError(
                  f"property_columns must be a list, got: {type(property_columns)}"
              )
          invalid_columns = set(property_columns).difference(
              dataframe.columns
          )
          if invalid_columns:
              raise ValueError(
                  "property_columns contains column(s) not found in dataframe: "
                  f"{list(invalid_columns)}"
              )
          existing_vectors = (
              set(property_columns)
              & self.__vertex_vector_property_lengths.keys()
          )
          if existing_vectors:
              raise ValueError(
                  "Non-vector property columns cannot be added to existing "
                  f"vector properties: {', '.join(sorted(existing_vectors))}"
              )
  
      # Save the DataFrame and Series types for future instantiations
      if self.__dataframe_type is None or self.__series_type is None:
          self.__dataframe_type = type(dataframe)
          self.__series_type = type(dataframe[dataframe.columns[0]])
      else:
          if type(dataframe) is not self.__dataframe_type:
              raise TypeError(
                  f"dataframe is type {type(dataframe)} but "
                  "the PropertyGraph was already initialized "
                  f"using type {self.__dataframe_type}"
              )
      TCN = self.type_col_name
      if vector_properties is not None:
          invalid_keys = {self.vertex_col_name, TCN}
          if property_columns:
              invalid_keys.update(property_columns)
          self._check_vector_properties(
              dataframe,
              vector_properties,
              self.__vertex_vector_property_lengths,
              invalid_keys,
          )
      if vector_property is not None:
          invalid_keys = {self.vertex_col_name, TCN, vertex_col_name}
          if property_columns:
              invalid_keys.update(property_columns)
          if vector_properties:
              invalid_keys.update(*vector_properties.values())
          d = {
              vector_property: [
                  col
                  for col in dataframe.columns
                  if col not in invalid_keys
              ]
          }
          invalid_keys.remove(vertex_col_name)
          self._check_vector_properties(
              dataframe,
              d,
              self.__vertex_vector_property_lengths,
              invalid_keys,
          )
          # Update vector_properties, but don't mutate the original
          if vector_properties is not None:
              d.update(vector_properties)
          vector_properties = d
  
      # Clear the cached values related to the number of vertices since more
      # could be added in this method.
      self.__num_vertices = None
      self.__vertex_type_value_counts = None  # Could update instead
  
      # Add `type_name` to the TYPE categorical dtype if necessary
      is_first_data = self.__vertex_prop_dataframe is None
      if is_first_data:
          # Initialize the __vertex_prop_dataframe using the same type
          # as the incoming dataframe.
          self.__vertex_prop_dataframe = self.__dataframe_type(
              columns=[self.vertex_col_name, TCN]
          )
          # Initialize the new columns to the same dtype as the appropriate
          # column in the incoming dataframe, since the initial merge may not
          # result in the same dtype. (see
          # https://github.com/rapidsai/cudf/issues/9981)
          if not index_is_set:
              self.__vertex_prop_dataframe = (
                  self.__update_dataframe_dtypes(
                      self.__vertex_prop_dataframe,
                      {
                          self.vertex_col_name: dataframe[
                              vertex_col_name
                          ].dtype
                      },
                  )
              )
          self.__vertex_prop_dataframe.set_index(
              self.vertex_col_name, inplace=True
          )
  
          # Use categorical dtype for the type column
          if self.__series_type is cudf.Series:
              cat_class = cudf.CategoricalDtype
          else:
              cat_class = pd.CategoricalDtype
          cat_dtype = cat_class([type_name], ordered=False)
      else:
          cat_dtype = self.__update_categorical_dtype(
              self.__vertex_prop_dataframe, TCN, type_name
          )
  
      # NOTE: This copies the incoming DataFrame in order to add the new
      # columns. The copied DataFrame is then merged (another copy) and then
      # deleted when out-of-scope.
  
      # Ensure that both the predetermined vertex ID column name and vertex
      # type column name are present for proper merging.
      tmp_df = dataframe.copy(deep=True)
      if not index_is_set:
          tmp_df[self.vertex_col_name] = tmp_df[vertex_col_name]
      elif tmp_df.index.name != self.vertex_col_name:
          tmp_df.index = tmp_df.index.rename(self.vertex_col_name)
  
      # FIXME: handle case of a type_name column already being in tmp_df
      tmp_df[TCN] = self.__series_type(
          type_name, index=tmp_df.index
      ).astype(cat_dtype)
  
      if property_columns:
          # all columns
          column_names_to_drop = set(tmp_df.columns)
          # remove the ones to keep
          column_names_to_drop.difference_update(
              property_columns + [self.vertex_col_name, TCN]
          )
      else:
          column_names_to_drop = {vertex_col_name}
  
      if index_is_set:
          column_names_to_drop -= {
              self.vertex_col_name,
              vertex_col_name,
          }
  
      if vector_properties:
          # Drop vector property source columns by default
          more_to_drop = set().union(*vector_properties.values())
          if property_columns is not None:
              more_to_drop.difference_update(property_columns)
          column_names_to_drop |= more_to_drop
          column_names_to_drop -= vector_properties.keys()
          self._create_vector_properties(tmp_df, vector_properties)
  
      tmp_df.drop(labels=column_names_to_drop, axis=1, inplace=True)
  
      # Save the original dtypes for each new column so they can be restored
      # prior to constructing subgraphs (since column dtypes may get altered
      # during merge to accommodate NaN values).
      if is_first_data:
          new_col_info = tmp_df.dtypes.items()
      else:
          new_col_info = self.__get_new_column_dtypes(
              tmp_df, self.__vertex_prop_dataframe
          )
      self.__vertex_prop_dtypes.update(new_col_info)
  
      if not index_is_set:
          tmp_df.set_index(self.vertex_col_name, inplace=True)
      tmp_df = self.__update_dataframe_dtypes(
          tmp_df, self.__vertex_prop_dtypes
      )
  
      if is_first_data:
          self.__vertex_prop_dataframe = tmp_df
      else:
          # Join on vertex ids (the index)
          # TODO: can we automagically determine when we to use concat?
          df = self.__vertex_prop_dataframe.join(
              tmp_df, how="outer", rsuffix="_NEW_"
          )
          cols = self.__vertex_prop_dataframe.columns.intersection(
              tmp_df.columns
          ).to_list()
          rename_cols = {f"{col}_NEW_": col for col in cols}
          new_cols = list(rename_cols)
          sub_df = df[new_cols].rename(columns=rename_cols)
          df.drop(columns=new_cols, inplace=True)
          # This only adds data--it doesn't replace existing data
          df.fillna(sub_df, inplace=True)
          self.__vertex_prop_dataframe = df
  
      # Update the vertex eval dict with the latest column instances
      self._update_eval_dict(
          self.__vertex_prop_eval_dict,
          self.__vertex_prop_dataframe,
          self.vertex_col_name,
      )
  
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 18 for calling the EXPERIMENTAL__PropertyGraph obj's underlying member method code with example usage: obj.add_vertex_data(dataframe, vertex_col_name, type_name, property_columns, vector_properties, vector_property) without return types