code: def _project_observable(self, input_key: str,
                              input_observable: Any,
                              get_hist_args: Dict[str, Any] = None,
                              projection_name_args: Dict[str, Any] = None,
                              **kwargs) -> Hist:
          if get_hist_args is None:
              get_hist_args = copy.deepcopy(kwargs)
          if projection_name_args is None:
              projection_name_args = copy.deepcopy(kwargs)
          get_hist_args.update({"observable": input_observable})
          hist = self.get_hist(**get_hist_args)
          projection_name_args.update(self.projection_information)
          projection_name_args.update(kwargs)
          projection_name_args.update({
              "input_key": input_key,
              "input_observable": input_observable,
              "input_hist": hist
          })
          projection_name = self.projection_name(**projection_name_args)
          logger.debug(f"hist: {hist}")
          for axis in self.additional_axis_cuts:
              logger.debug(f"Apply additional axis hist range: {axis.name}")
              axis.apply_range_set(hist)
          if self.projection_dependent_cut_axes == []:
              self.projection_dependent_cut_axes.append([])
          duplicated_axes = [
              PDCA
              for PA in self.projection_axes
              for PDCA_group in self.projection_dependent_cut_axes
              for PDCA in PDCA_group
              if PDCA.axis_type == PA.axis_type
          ]
          if duplicated_axes:
              raise ValueError(
                  f"Axis {duplicated_axes} is in the projection axes and the projection dependent cut axes."
                  " This configuration is not allowed, as the range in the PDCA will be overwritten by the projection axes!"
                  " Please revise your configuration."
              )
          hists = []
          for i, axes in enumerate(self.projection_dependent_cut_axes):
              for axis in axes:
                  logger.debug(f"Apply projection dependent hist range: {axis.name}")
                  axis.apply_range_set(hist)
              projected_hist = self.call_projection_function(hist)
              projected_hist.SetName(f"{projection_name}_{i}")
              hists.append(projected_hist)
              self.cleanup_cuts(hist, cut_axes = axes)
          self.cleanup_cuts(hist, cut_axes = self.additional_axis_cuts)
          output_hist = hists[0]
          for temp_hist in hists[1:]:
              output_hist.Add(temp_hist)
          output_hist.SetName(projection_name)
          output_hist.SetDirectory(0)
          return output_hist, projection_name, projection_name_args