def METHOD_NAME(self, epoch: int, train: bool, metrics: tp.Dict[str, float]) -> None:
    """
    Save metrics at specific training epoch.
    Parameters
    ----------
    epoch : int
        Current epoch
    train : bool
        Flag that indicates whether metrics are calculated on train or test data
    metrics: dict
        Values for each of metrics defined in `__init__` method of this class
    """
    self.passed_iterations = epoch + 1
    self._content["passed_iterations"] = self.passed_iterations
    total_iterations = max(self._content["total_iterations"], self.passed_iterations)
    self._content["total_iterations"] = total_iterations
    self._values["meta"]["iteration_count"] = total_iterations
    assert len(self._values["iterations"]) in (epoch, epoch + 1), \
        "Data for epochs should be passed successively (wrong epoch number)"
    time_from_start: float = time.time() - self._start_time
    should_redraw: bool = len(self._values["iterations"]) == epoch + 1
    if len(self._values["iterations"]) == epoch:
        self._values["iterations"].append({
            "learn": [],
            "test": [],
            "iteration": epoch,
            "passed_time": time_from_start,
        })
        remaining_time = self.estimate_remaining_time(time_from_start)
        if remaining_time is not None:
            self._values["iterations"][-1]["remaining_time"] = remaining_time
    key: str = "learn" if train else "test"
    value: List[float] = self.construct_metrics_array(
        self._train_metrics_positions if train else self._test_metrics_positions, metrics)
    self._values["iterations"][-1].update({key: value})
    if should_redraw:
        self._widget.update_data(self._data)