text: import os
  import os.path as osp
  import argparse
  import pickle 
  import matplotlib
  import matplotlib.pyplot as plt
  import numpy as np
  import random
  from functools import reduce
  from operator import itemgetter
  from argparse import Namespace
  
  def parse_args():
      parser = argparse.ArgumentParser()
      parser.add_argument('-appstr', type=str, default='unknown')
      parser.add_argument('-ntask', type=int, default=1, help='number of tasks')
      parser.add_argument("-bmin", type=int, default=1, help ='minimum value for bandit budget')
      parser.add_argument("-bmax", type=int, default=8, help ='maximum value for bandit budget')
      parser.add_argument("-eta", type=int, default=2, help ='base value for bandit structure')
      parser.add_argument("-Nloop", type=int, default=1, help ='number of bandit loops')
      parser.add_argument('-baseline', type=float, default=None)
      parser.add_argument('-explist', nargs='+', help='a list of repeated experiment for error bar plots', required=True)
      parser.add_argument('-deleted_tuners', nargs='+', help='a list of tuners not plotting', default=None)
      return parser.parse_args()
  
  def gen_source(args, expid=None):
      my_source = f'./{args.appstr}_ntask{args.ntask}_bandit{args.bmin}-{args.bmax}-{args.eta}_Nloop{args.Nloop}_expid{expid}.pkl'
      return my_source
  
  
  def data_process_single_exp(args, expid=None):
      my_source = gen_source(args, expid=expid)
      results_summary = pickle.load(open(my_source, "rb"))
         
      styles = {'GPTuneBand': ['GPTuneBand','#C33734','dashed', "o"],
                'GPTune': ['GPTune','#2ca02c', 'dashed', '*'], 
                'hpbandster': ['HpBandSter', '#ff7f0e', 'dashed', 'p'],
                'TPE': ['TPE', '#9467bd', 'dashed', '1'],
                'opentuner': ['OpenTuner', '#1f77b4',  'dashed', 'p']}
      
      tuners = []
      for item in results_summary:
          tuners.append(item[0])
       
       
      data_summary_dict = {}
      for j, item in enumerate(results_summary):
          tuner_data_summary = {}
          for i in range(args.ntask):
              # tuning_history_data = historical_best(item[i+1][2][1])
              tuning_history_data = [x for x in historical_best(item[i+1][2][1])]
              tuner_data_summary[item[i+1][0]] = [item[i+1][2][0], tuning_history_data]
              
          data_summary_dict[tuners[j]] = tuner_data_summary
          
          # print("Processed data for", tuners[j])
          # print(tuner_data_summary)
          # print()
      return data_summary_dict, styles
  
  def data_process(args):
      if len(args.explist) == 1:
          return data_process_single_exp(args, expid=args.explist[0])
      else:
          data_summary = []
          for expid in args.explist:
              data_summary_cur, styles = data_process_single_exp(args, expid=expid)
              data_summary.append(data_summary_cur)
          return data_summary, styles
      
  
  def historical_best(data):
      for i in range(len(data)-1):
          data[i+1] = data[i] if data[i] < data[i+1] else data[i+1]
      return data
  
  def plot_history(args, data_summary_dict_set, styles, baseline=None,
                   deleted_tuners=None):
  
      MARKERSIZE=9
      fontsize=17
      
      # tuners = list(data_summary_dict_set[0].keys())
      tuners = []
      tuners = list(reduce(lambda a,b: a.intersection(b), [set(x.keys()) for x in data_summary_dict_set]) )
      tuners = ['GPTune','GPTuneBand']
      # print("tuners:", tuners) 
      
      N_tuners = len(tuners)
      N_exps = len(args.explist)
      
      # get a list of tasks
      values_view = data_summary_dict_set[0].values()
      value_iterator = iter(values_view)
      first_tuner_info = next(value_iterator)
      task_set = list(first_tuner_info.keys())
  
      for task in task_set:
          bugets_set = []
          mean_results_set = []
          std_results_set = []
          for i,tuner in enumerate(tuners):
              tuner_info = data_summary_dict_set[0][tuner]
              bugets_set.append(data_summary_dict_set[0][tuner][task][0])
              results_set=[]
              for exp_j in range(N_exps):
                  results_set.append(data_summary_dict_set[exp_j][tuner][task][1])
              mean_results_set.append(np.mean(results_set, axis=0))
              std_results_set.append(np.std(results_set, ddof=0,axis=0))
              
          expname = '-'.join(args.explist)
          my_source = gen_source(args, expid=expname)
          filename = os.path.splitext(os.path.basename(my_source))[0]
              
          fig, ax = plt.subplots(nrows=1, ncols=1)
          if baseline != None:
              ax.plot(bugets_set[0], 
                      args.fmin*np.ones(len(bugets_set)), 
                      'k--', label="True")
  
          for i in range(N_tuners):
              if args.deleted_tuners == None or tuners[i] not in args.deleted_tuners:
                  print(tuners[i])
                  ax.plot(bugets_set[i], 
                          mean_results_set[i],
                          color=styles[tuners[i]][1], 
                          label=styles[tuners[i]][0],
                          linestyle=styles[tuners[i]][2],
                          marker=styles[tuners[i]][3],
                          markersize=MARKERSIZE)
                  ax.fill_between(bugets_set[i], 
                                  mean_results_set[i]+std_results_set[i], 
                                  mean_results_set[i]-std_results_set[i],
                                  color=styles[tuners[i]][1], 
                                  alpha=0.25)
          
          ax.set_xlabel('Tuning cost', fontsize=fontsize)
          ax.set_ylabel('Runtime', fontsize=fontsize)
          ax.set_xlim([0, 16.5])
          xticks=np.arange(0,18,2)
          ax.set_xticks(xticks)
          ax.set_xticklabels(xticks,Fontsize=fontsize)
          yticks = np.arange(45,76, 5)
          ax.set_ylim([44,76])
          ax.set_yticks(yticks)
          ax.set_yticklabels(yticks,Fontsize=fontsize)
          plt.tight_layout()
          plt.legend(loc='upper right',prop={'size': fontsize-3})
          plt.grid()
          savepath = os.path.join("./", f"Tuning_history_{filename}.pdf")    
          plt.savefig(savepath)
          print("Figure saved: ", savepath)
  
  def main(args):
      print()
      print("plotting args:", args)
      data_summary_dict_set, styles = data_process(args)
      plot_history(args, data_summary_dict_set, styles)
  
      
  if __name__ == "__main__":
      main(parse_args())