code: def plot_3d(
      points: np.ndarray,
      labels: np.ndarray,
      colors: Optional[List[str]] = None,
      save: bool = True,
      f_name: str = "",
  ) -> "matplotlib.figure.Figure":  # pragma: no cover
      """
      Generates a 3-D plot in of the provided points where the labels define the color that will be used to color each
      data point. Concretely, the color of points[i] is defined by colors(labels[i]). Thus, there should be as many labels
       as colors.
  
      :param points: arrays with 3-D coordinates of the plots to be plotted.
      :param labels: array of integers that determines the color used in the plot for the data point.
          Need to start from 0 and be sequential from there on.
      :param colors: Optional argument to specify colors to be used in the plot. If provided, this array should contain
      as many colors as labels.
      :param save:  When set to True, saves image into a file inside `ART_DATA_PATH` with the name `f_name`.
      :param f_name: Name used to save the file when save is set to True.
      :return: A figure object.
      """
      # Disable warnings of unused import because all imports in this block are required
      # pylint: disable=W0611
      # import matplotlib
      import matplotlib.pyplot as plt
  
      from mpl_toolkits import mplot3d  # noqa: F401
  
      if colors is None:  # pragma: no cover
          colors = []
          for i in range(len(np.unique(labels))):
              colors.append("C" + str(i))
      else:
          if len(colors) != len(np.unique(labels)):
              raise ValueError(
                  "The amount of provided colors should match the number of labels in the 3pd plot."
              )
  
      fig = plt.figure()
      axis = plt.axes(projection="3d")
  
      for i, coord in enumerate(points):
          try:
              color_point = labels[i]
              axis.scatter3D(
                  coord[0],
                  coord[1],
                  coord[2],
                  color=colors[color_point],
              )
          except IndexError:
              raise ValueError(
                  "Labels outside the range. Should start from zero and be sequential there after"
              ) from IndexError
      if save:  # pragma: no cover
          file_name = os.path.realpath(
              os.path.join(config.ART_DATA_PATH, f_name)
          )
          folder = os.path.split(file_name)[0]
  
          if not os.path.exists(folder):
              os.makedirs(folder)
          fig.savefig(file_name, bbox_inches="tight")
          logger.info("3d-plot saved to %s.", file_name)
  
      return fig
  
file_path: adversarial-robustness-toolbox/art/visualization.py
imports: from __future__ import absolute_import, division, print_function, unicode_literals
  import logging
  import os.path
  from typing import List, Optional, TYPE_CHECKING
  import numpy
  from art import config
label_desc: Use image node_id 4 for calling a global function with example usage: plot_3d(points, labels, colors, save, f_name) and returns: fig