docstr: Add information of learning curve to report.
  
  Args:
      notes(str): Explain the block
      history(:dict of dict): a dict of training log dict.
          key: epoch index
          value: learning epoch information
                  Each dict has two keys:
                      - params: a dict of params on current epochs (Optional)
                      - val_scores: a dict of which key is the metric name
                                and value is metric value
      best_idx(str):
          - the best epoch based on benchmark metric, corresponding the `history` dict key
      benchmark_metric(:str): the metric used for benchmarking during learning
      benchmark_threshold(:float, Optional): the benchmarking threshold to accept the training
      training_params(:dict): a dict of which key is training parameter name and
                              value is training parameter value
code: def draw_learning_curve(
      self,
      notes: str,
      *,
      history: dict,
      best_idx: str,
      benchmark_metric=None,
      benchmark_threshold=None,
      training_params=None,
  ):
      """
      Add information of learning curve to report.
  
      Args:
          notes(str): Explain the block
          history(:dict of dict): a dict of training log dict.
              key: epoch index
              value: learning epoch information
                      Each dict has two keys:
                          - params: a dict of params on current epochs (Optional)
                          - val_scores: a dict of which key is the metric name
                                    and value is metric value
          best_idx(str):
              - the best epoch based on benchmark metric, corresponding the `history` dict key
          benchmark_metric(:str): the metric used for benchmarking during learning
          benchmark_threshold(:float, Optional): the benchmarking threshold to accept the training
          training_params(:dict): a dict of which key is training parameter name and
                                  value is training parameter value
      """
      from xai.graphs import graph_generator
  
      # -- Draw Content --
      if not (notes is None):
          self.html.article[-1].items.append(
              self.html.add_paragraph(text=notes)
          )
      if training_params is not None:
          self.html.article[-1].items.append(
              self.html.add_paragraph(
                  text="Training Parameters", style="BI"
              )
          )
          self.html.article[-1].items.append(
              self.html.add_table_with_dict(data=training_params)
          )
  
      self.html.article[-1].items.append(
          self.html.add_paragraph(text="Learning Curve", style="BI")
      )
      self.html.article[-1].items.append(
          self.html.add_paragraph(
              text="The metric results from several training epochs are shown "
              "in the figure."
          )
      )
      benchmark_dict = dict()
      benchmark_dict["Benchmark metric"] = benchmark_metric
      benchmark_dict["Benchmark value"] = benchmark_threshold
      self.html.article[-1].items.append(
          self.html.add_table_with_dict(data=benchmark_dict)
      )
  
      image_path = "%s/deep_learning_curve.png" % self.figure_path
      image_path = graph_generator.EvaluationLinePlot(
          figure_path=image_path,
          data=history,
          title="training_history",
          x_label="Steps",
          y_label="Metrics Score",
      ).draw(
          benchmark_metric=benchmark_metric,
          benchmark_value=benchmark_threshold,
      )
      self.html.article[-1].items.append(
          self.html.add_image(src=image_path, alt="hyper_history")
      )
  
      self.html.article[-1].items.append(
          self.html.add_paragraph(
              text="Best Epoch from Training", style="BI"
          )
      )
      self.html.article[-1].items.append(
          self.html.add_paragraph(
              text="The best iteration is %s" % str(best_idx)
          )
      )
  
      self.html.article[-1].items.append(
          self.html.add_paragraph(
              text="Validation Results:", style="BI"
          )
      )
      if best_idx not in history:
          best_idx = str(best_idx)
      validation_result = dict()
      for param_name, param_value in history[best_idx][
          "val_scores"
      ].items():
          if param_name == benchmark_metric:
              validation_result[param_name.capitalize()] = (
                  "%s (benchmarking metric)" % param_value
              )
          else:
              validation_result[param_name.capitalize()] = param_value
      self.html.article[-1].items.append(
          self.html.add_table_with_dict(data=validation_result)
      )
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import copy
  import os
  import tempfile
  import warnings
  import shutil
  from typing import Tuple, Dict, List
  import numpy
  from xai import MODE
  from xai.data.explorer import CategoricalStats, NumericalStats, TextStats, DatetimeStats
  from xai.formatter.contents import Header, Title, SectionTitle
  from xai.formatter.hypertext_markup.publisher import CustomHtml, Div
  from xai.formatter.report.section import OverviewSection, DetailSection
  from xai.formatter.writer import Writer
label_desc: Use image node_id 28 for calling the HtmlWriter obj's underlying member method code with example usage: obj.draw_learning_curve(notes) without return types