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