text: #! /usr/bin/env python
  # -*- coding: utf-8 -*-
  """Creates ERTs and convergence figures for multiple algorithms."""
  from __future__ import absolute_import, print_function
  import os
  import matplotlib.pyplot as plt
  import numpy
  import warnings
  from pdb import set_trace
  from .. import toolsdivers, toolsstats, bestalg, pproc, genericsettings, htmldesc, ppfigparam, ppfig
  from .. import testbedsettings
  from .. import captions
  from ..ppfig import save_figure, get_plotting_styles, getFontSize
  from ..pptex import color_to_latex, marker_to_latex, marker_to_html, writeLabels
  
  show_significance = 0.01  # for zero nothing is shown
  
  refcolor = 'wheat'
  
  show_algorithms = []
  fontsize = 14.0
  legend_text_max_len = 14
  legend = False
  
  def legend_fontsize_scaler(number_of_entries=None):
      """return a fontsize scaling factor depending on the number of entries
      in the legend.
  
      Works currently well with fontsize 14, where a legend with up to ~30
      entries will still fit into the figure.
      """
      if not number_of_entries:
          number_of_entries = len(plt.gca().get_legend_handles_labels()[1])
      return 2.55 / (number_of_entries + 1.5)**0.5
  
  def fix_styles(plotting_styles, line_styles):
      """a short hack to fix length of styles"""
      m = len(line_styles)
      while len(line_styles) < len(plotting_styles.algorithm_list):
          line_styles.append(line_styles[len(line_styles) % m])
      for i in range(len(line_styles)):
          if plotting_styles.in_background:
              line_styles[i].update(plotting_styles.ppfigs_styles)
          else:
              line_styles[i].update({'linewidth': 4 - min([2, i / 3.0]),  # thinner lines over thicker lines
                                     'markeredgewidth': 3 - min([2, i / 2.0]),
                                     'markersize': int(line_styles[i]['markersize'] / 2),
                                     'markerfacecolor': 'None'})
  
  def prepare_scaling_figure_caption():
  
      scaling_figure_caption_start_fixed = (r"""Expected running time (\ERT\ in number of $f$-evaluations
                      as $\log_{10}$ value), divided by dimension for target function value $!!PPFIGS-FTARGET!!$
                      versus dimension. Slanted grid lines indicate quadratic scaling with the dimension. """
                                            )
  
      scaling_figure_caption_start_rlbased = (r"""Expected running time (\ERT\ in number of $f$-evaluations
                          as $\log_{10}$ value) divided by dimension versus dimension. The target function value
                          is chosen such that !!THE-REF-ALG!! just failed to achieve
                          an \ERT\ of $!!PPFIGS-FTARGET!!\times\DIM$. """
                                              )
  
      scaling_figure_caption_end = (
          r"Different symbols " +
          r"correspond to different algorithms given in the legend of #1. " +
          r"Light symbols give the maximum number of function evaluations from the longest trial " +
          r"divided by dimension. " +
          (r"Black stars indicate a statistically better result compared to all other algorithms " +
           r"with $p<0.01$ and Bonferroni correction number of dimensions (six).  ")
          if show_significance else ''
      )
  
      scaling_figure_caption_fixed = scaling_figure_caption_start_fixed + scaling_figure_caption_end
      scaling_figure_caption_rlbased = scaling_figure_caption_start_rlbased + scaling_figure_caption_end
  
      if testbedsettings.current_testbed.name in [testbedsettings.suite_name_bi_ext,
                                                  testbedsettings.suite_name_cons,
                                                  testbedsettings.suite_name_ls,
                                                  testbedsettings.suite_name_mixint,
                                                  testbedsettings.suite_name_bi_mixint,
                                                  testbedsettings.suite_name_tt,
                                                  testbedsettings.suite_name_mg,
                                                  testbedsettings.suite_name_tt_bi,
                                                  testbedsettings.suite_name_mg_bi]:
          # NOTE: no runlength-based targets supported yet
          figure_caption = scaling_figure_caption_fixed
      elif testbedsettings.current_testbed.name in [testbedsettings.suite_name_single,
                                                    testbedsettings.suite_name_single_noisy,
                                                    testbedsettings.suite_name_bi]:
          if genericsettings.runlength_based_targets:
              figure_caption = scaling_figure_caption_rlbased
          else:
              figure_caption = scaling_figure_caption_fixed
      else:
          warnings.warn("Current settings do not support ppfigdim caption.")
  
      return figure_caption
  
  def scaling_figure_caption(for_html = False):
  
  
      if for_html:
          figure_caption = htmldesc.getValue('##bbobppfigslegend' +
                                             testbedsettings.current_testbed.scenario + '##')
      else:
          figure_caption = prepare_scaling_figure_caption()
  
      return captions.replace(figure_caption, html=for_html)
  
  
  def prepare_ecdfs_figure_caption():
      testbed = testbedsettings.current_testbed
      refalgtext = (
                    r"As reference algorithm, !!THE-REF-ALG!! " +
                    r"is shown as light " +
                    r"thick line with diamond markers."
                   )
  
      ecdfs_figure_caption_standard = (
                  r"Bootstrapped empirical cumulative distribution of the number " +
                  r"of objective function evaluations divided by dimension " +
                  r"(FEvals/DIM) for $!!NUM-OF-TARGETS-IN-ECDF!!$ " +
                  r"targets with target precision in !!TARGET-RANGES-IN-ECDF!! " +
                  r"for all functions and subgroups in #1-D. "
                  )
      ecdfs_figure_caption_rlbased = (
                  r"Bootstrapped empirical cumulative distribution of the number " +
                  r"of objective function evaluations divided by dimension " +
                  r"(FEvals/DIM) for all functions and subgroups in #1-D. " +
                  r"The targets are chosen from !!TARGET-RANGES-IN-ECDF!! " +
                  r"such that !!THE-REF-ALG!! just " +
                  r"not reached them within a given budget of $k$ $\times$ DIM, " +
                  r"with $!!NUM-OF-TARGETS-IN-ECDF!!$ different values of $k$ " +
                  r"chosen equidistant in logscale within the interval " +
                  r"$\{0.5, \dots, 50\}$. "
                  )
  
      if testbed.name in [testbedsettings.suite_name_bi_ext,
                          testbedsettings.suite_name_cons,
                          testbedsettings.suite_name_ls,
                          testbedsettings.suite_name_mixint,
                          testbedsettings.suite_name_bi_mixint,
                          testbedsettings.suite_name_tt,
                          testbedsettings.suite_name_mg,
                          testbedsettings.suite_name_tt_bi,
                          testbedsettings.suite_name_mg_bi]:
  
          # NOTE: no runlength-based targets supported yet
          figure_caption = ecdfs_figure_caption_standard
      elif testbed.name in [testbedsettings.suite_name_single,
                            testbedsettings.suite_name_single_noisy,
                            testbedsettings.suite_name_bi]:
          if genericsettings.runlength_based_targets:
              figure_caption = ecdfs_figure_caption_rlbased + refalgtext
          else:
              figure_caption = ecdfs_figure_caption_standard + refalgtext
      else:
          warnings.warn("Current settings do not support ppfigdim caption.")
  
      return figure_caption
  
  
  def ecdfs_figure_caption(for_html = False, dimension = 0):
  
      if for_html:
          key = '##bbobECDFslegend%s##' % testbedsettings.current_testbed.scenario
          caption = htmldesc.getValue(key)
      else:
          caption = prepare_ecdfs_figure_caption()   
  
      return captions.replace(caption, html=for_html)
  
  
  def get_ecdfs_single_fcts_caption():
      ''' Returns figure caption for single function ECDF plots. '''
  
      if genericsettings.runlength_based_targets:
          s = (r"""Empirical cumulative distribution of simulated (bootstrapped) runtimes in number
               of objective function evaluations divided by dimension (FEvals/DIM) for  
               targets in !!TARGET-RANGES-IN-ECDF!! that have just not
               been reached by !!THE-REF-ALG!!
               in a given budget of $k$ $\times$ DIM, with $!!NUM-OF-TARGETS-IN-ECDF!!$ 
               different values of $k$ chosen equidistant in logscale within the interval $\{0.5, \dots, 50\}$.
               Shown are functions $f_{#1}$ to $f_{#2}$ and all dimensions. """)
      else:
          s = (r"""Empirical cumulative distribution of simulated (bootstrapped) runtimes in number
               of objective function evaluations divided by dimension (FEvals/DIM) for the 
               $!!NUM-OF-TARGETS-IN-ECDF!!$ targets !!TARGET-RANGES-IN-ECDF!!
               for functions $f_{#1}$ to $f_{#2}$ and all dimensions. """
               )
  
      return captions.replace(s)
  
  def get_ecdfs_all_groups_caption():
      ''' Returns figure caption for ECDF plots aggregating over function groups. '''
      
      if genericsettings.runlength_based_targets:
          s = (r"""Empirical cumulative distribution of simulated (bootstrapped)
               runtimes, measured in number of objective function evaluations 
               divided by dimension (FEvals/DIM) for all function groups and all 
               dimensions and for those targets in
               !!TARGET-RANGES-IN-ECDF!! that have just not been reached by 
               !!THE-REF-ALG!! in a given budget of $k$ $\times$ DIM, with 
               $!!NUM-OF-TARGETS-IN-ECDF!!$ different values of $k$ chosen 
               equidistant in logscale within the interval $\{0.5, \dots, 50\}$.             
               The aggregation over all !!TOTAL-NUM-OF-FUNCTIONS!! 
               functions is shown in the last plot."""
               )
      else:
          s = (r"""Empirical cumulative distribution of simulated (bootstrapped)
               runtimes, measured in number of objective function evaluations,
               divided by dimension (FEvals/DIM) for the $!!NUM-OF-TARGETS-IN-ECDF!!$ 
               targets !!TARGET-RANGES-IN-ECDF!! for all function groups and all 
               dimensions. The aggregation over all !!TOTAL-NUM-OF-FUNCTIONS!! 
               functions is shown in the last plot."""
               )
      return captions.replace(s)
  
  def get_ecdfs_single_functions_single_dim_caption():
      ''' Returns figure caption for single function ECDF plots
          showing the results of 2+ algorithms in a single dimension. '''
      
      if genericsettings.runlength_based_targets:
          s = (r"""Empirical cumulative distribution of simulated (bootstrapped)
               runtimes, measured in number of objective function evaluations 
               divided by dimension (FEvals/DIM) in 
               dimension #1 and for those targets in
               !!TARGET-RANGES-IN-ECDF!! that have just not been reached by 
               !!THE-REF-ALG!! in a given budget of $k$ $\times$ DIM, with 
               $!!NUM-OF-TARGETS-IN-ECDF!!$ different values of $k$ chosen 
               equidistant in logscale within the interval $\{0.5, \dots, 50\}$."""
               )
      else:
          s = (r"""Empirical cumulative distribution of simulated (bootstrapped)
               runtimes, measured in number of objective function evaluations,
               divided by dimension (FEvals/DIM) for the $!!NUM-OF-TARGETS-IN-ECDF!!$ 
               targets !!TARGET-RANGES-IN-ECDF!! in dimension #1."""
               )
      return captions.replace(s)
  
  def plotLegend(handles, maxval=None):
      """Display right-side legend.
      
      Sorted from smaller to larger y-coordinate values.
      
      """
      ys = {}
      lh = 0 # Number of labels to display on the right
      if not maxval:
          maxval = []
          for h in handles:
              x2 = []
              y2 = []
              for i in h:
                  x2.append(plt.getp(i, "xdata"))
              x2 = numpy.sort(numpy.hstack(x2))
              maxval.append(max(x2))
          maxval = max(maxval)
  
      for h in handles:
          x2 = []
          y2 = []
  
          for i in h:
              x2.append(plt.getp(i, "xdata"))
              y2.append(plt.getp(i, "ydata"))
  
          x2 = numpy.array(numpy.hstack(x2))
          y2 = numpy.array(numpy.hstack(y2))
          tmp = numpy.argsort(x2)
          x2 = x2[tmp]
          y2 = y2[tmp]
          h = h[-1]
  
          # ybis is used to sort in case of ties
          try:
              tmp = x2 <= maxval
              y = y2[tmp][-1]
              ybis = y2[tmp][y2[tmp] < y]
              if len(ybis) > 0:
                  ybis = ybis[-1]
              else:
                  ybis = y2[tmp][-2]
              ys.setdefault(y, {}).setdefault(ybis, []).append(h)
              lh += 1
          except IndexError:
              pass
  
      if len(show_algorithms) > 0:
          lh = min(lh, len(show_algorithms))
  
      if lh <= 1:
          lh = 2
  
      ymin, ymax = plt.ylim()
      xmin, xmax = plt.xlim()
  
      i = 0 # loop over the elements of ys
      for j in sorted(ys.keys()):
          for k in sorted(ys[j].keys()):
  			# enforce that a "best" algorithm comes first in case of equality
              tmp = []
              for h in ys[j][k]:
                  if 'best' in plt.getp(h, 'label'):
                      tmp.insert(0, h)
                  else:
                      tmp.append(h)
              #tmp.reverse()
              ys[j][k] = tmp
  
              for h in ys[j][k]:
                  if (not plt.getp(h, 'label').startswith('_line') and
                      (len(show_algorithms) == 0 or
                       plt.getp(h, 'label') in show_algorithms)):
                      y = 0.02 + i * 0.96/(lh-1)
                      # transform y in the axis coordinates
                      #inv = plt.gca().transLimits.inverted()
                      #legx, ydat = inv.transform((.9, y))
                      #leglabx, ydat = inv.transform((.92, y))
                      #set_trace()
  
                      ydat = 10**(y * numpy.log10(ymax/ymin)) * ymin
                      legx = 10**(.85 * numpy.log10(xmax/xmin)) * xmin
                      leglabx = 10**(.87 * numpy.log10(xmax/xmin)) * xmin
                      tmp = {}
                      for attr in ('lw', 'linestyle', 'marker',
                                   'markeredgewidth', 'markerfacecolor',
                                   'markeredgecolor', 'markersize', 'zorder'):
                          tmp[attr] = plt.getp(h, attr)
                      plt.plot((maxval, legx), (j, ydat),
                               color=plt.getp(h, 'markeredgecolor'), **tmp)
  
                      plt.text(leglabx, ydat,
                               plt.getp(h, 'label'), horizontalalignment="left",
                               verticalalignment="center", size=fontsize)
                      i += 1
  
      plt.xlim(xmin, xmax)
      plt.ylim(ymin, ymax)
      if maxval:
          plt.axvline(maxval, color='k')
  
  def beautify(legend=False, rightlegend=False):
      """Customize figure format.
  
      adding a legend, axis label, etc
  
      :param bool legend: if True, display a box legend
      :param bool rightlegend: if True, makes some space on the right for
                               legend
  
      """
      # Get axis handle and set scale for each axis
      axisHandle = plt.gca()
      axisHandle.set_xscale("log")
      try:
          axisHandle.set_yscale("log")
      except OverflowError:
          set_trace()
  
      # Grid options
      axisHandle.yaxis.grid(True)
  
      ymin, ymax = plt.ylim()
  
      # quadratic slanted "grid"
      if 1 < 3:
          for i in range(-2, 7, 1 if ymax < 1e5 else 2):
              plt.plot((0.2, 20000), (10**i, 10**(i + 5)), 'k:',
                       linewidth=0.5)  # grid should be on top
      else:  # to be removed
          plt.plot((2,200), (1, 1e2), 'k:', zorder=-1)  # -1 -> plotted below?
          # plt.plot((2,200), (1, 1e4), 'k:', zorder=-1)
          plt.plot((2,200), (1e3, 1e5), 'k:', zorder=-1)
          # plt.plot((2,200), (1e3, 1e7), 'k:', zorder=-1)
          plt.plot((2,200), (1e6, 1e8), 'k:', zorder=-1)
          # plt.plot((2,200), (1e6, 1e10), 'k:', zorder=-1)
  
      plt.ylim(10**-0.2, ymax) # Set back the default maximum.
  
      # ticks on axes
      #axisHandle.invert_xaxis()
      dimticklist = testbedsettings.current_testbed.dimensions_to_display
      dimannlist = testbedsettings.current_testbed.dimensions_to_display
      # TODO: All these should depend on (xlim, ylim)
  
      axisHandle.set_xticks(dimticklist)
      axisHandle.set_xticklabels([str(n) for n in dimannlist])
  
      dim_min_margin = testbedsettings.current_testbed.dimensions_to_display[0] * 0.9
      dim_max_margin = testbedsettings.current_testbed.dimensions_to_display[-1] * 1.125
  
      if rightlegend:
          plt.xlim(  dim_min_margin,  10 ** (numpy.log10(dim_max_margin / dim_min_margin)*1.25) * dim_min_margin)
      else:
          plt.xlim(dim_min_margin, dim_max_margin)
  
      if 1 < 3:
          tick_locs = [n for n in axisHandle.get_yticks()
                       if n > plt.ylim()[0] and n < plt.ylim()[1]]
          tick_labels = ['%d' % round(numpy.log10(n)) if n < 1e10  # assure 1 digit for uniform figure sizes
                         else '' for n in tick_locs]
          axisHandle.set_yticks(tick_locs)
          axisHandle.set_yticklabels(tick_labels)
      else:  # old code for debugging purpose, just remove after Sept 2017
          tmp = axisHandle.get_yticks()
          tmp2 = []
          for i in tmp:
              tmp2.append('%d' % round(numpy.log10(i)))
          axisHandle.set_yticklabels(tmp2, fontsize=ppfig.getFontSize(tmp2))
  
      if legend:
          toolsdivers.legend(loc=0, numpoints=1,
                             fontsize=fontsize * legend_fontsize_scaler())
  
      if genericsettings.scaling_plots_with_axis_labels:
          plt.xlabel('dimension')
          plt.ylabel('log10(# f-evals / dimension)')
  
  
  def generateData(dataSet, target):
      """Returns an array of results to be plotted.
  
      Oth column is ert, 1st is the success rate, 2nd the number of
      successes, 3rd the mean of the number of function evaluations, and
      4th the median of number of function evaluations of successful runs
      or numpy.nan.
  
      """
      res = []
  
      data = dataSet.detEvals([target])[0]
      succ = (numpy.isnan(data) == False)
      data[numpy.isnan(data)] = dataSet.maxevals[numpy.isnan(data)]
      res.extend(toolsstats.sp(data, issuccessful=succ, allowinf=False))
      res.append(numpy.mean(data))
      if res[2] > 0:
          res.append(toolsstats.prctile(data[succ], 50)[0])
      else:
          res.append(numpy.nan)
      res[3] = numpy.max(dataSet.maxevals)
      return res
  
  
  def main(dictAlg, html_file_prefix, sorted_algorithms=None, output_dir='ppdata', latex_commands_file=''):
      """From a DataSetList, returns figures showing the scaling: ERT/dim vs dim.
      
      One function and one target per figure.
      
      ``target`` can be a scalar, a list with one element or a 
      ``pproc.TargetValues`` instance with one target.
      
      ``sortedAlgs`` is a list of string-identifies (folder names)
      
      """
      # target becomes a TargetValues "list" with one element
      target = testbedsettings.current_testbed.ppfigs_ftarget
      target = pproc.TargetValues.cast([target] if numpy.isscalar(target) else target)
      assert isinstance(target, pproc.TargetValues)
      if len(target) != 1:
          raise ValueError('only a single target can be managed in ppfigs, ' + str(len(target)) + ' targets were given')
      
      funInfos = ppfigparam.read_fun_infos()    
  
      dictFunc = pproc.dictAlgByFun(dictAlg)
      if sorted_algorithms is None:
          sorted_algorithms = sorted(dictAlg.keys())
  
      plotting_style_list = get_plotting_styles(sorted_algorithms)
      styles = [d.copy() for d in genericsettings.line_styles]  # deep copy
      default_styles = [d.copy() for d in genericsettings.line_styles]
      if not os.path.isdir(output_dir):
          os.mkdir(output_dir)
      for f in dictFunc:
          filename = os.path.join(output_dir, 'ppfigs_f%03d' % (f))
          handles = []
          for plotting_style in plotting_style_list:
              algorithm_list = plotting_style.algorithm_list
              line_styles = [d.copy() for d in default_styles]
              fix_styles(plotting_style, line_styles)  #
              for i, alg in enumerate(algorithm_list):
                  dictDim = dictFunc[f][alg].dictByDim()  # this does not look like the most obvious solution
  
                  #Collect data
                  dimert = []
                  ert = []
                  dimnbsucc = []
                  ynbsucc = []
                  nbsucc = []
                  dimmaxevals = []
                  maxevals = []
                  dimmedian = []
                  medianfes = []
                  for dim in sorted(dictDim):
                      assert len(dictDim[dim]) == 1
                      entry = dictDim[dim][0]
                      data = generateData(entry, target((f, dim))[0]) # TODO: here we might want a different target for each function
                      if 1 < 3 or data[2] == 0: # No success
                          dimmaxevals.append(dim)
                          maxevals.append(float(data[3])/dim)
                      if data[2] > 0:
                          dimmedian.append(dim)
                          medianfes.append(data[4]/dim)
                          dimert.append(dim)
                          ert.append(float(data[0])/dim)
                          if data[1] < 1.:
                              dimnbsucc.append(dim)
                              ynbsucc.append(float(data[0])/dim)
                              nbsucc.append('%d' % data[2])
                  # Draw lines
                  if 1 < 3:  # new version
                      # omit the line if a point in between is missing
                      for idim in range(len(dimert)):
                          # plot line only if next dim < 2.1*dim (a hack)
                          if idim < len(dimert) - 1 and dimert[idim + 1] < 2.1 * dimert[idim]:
                              tmp = plt.plot(dimert[idim:idim+2], ert[idim:idim+2], **line_styles[i]) #label=alg, )
                          else:  # plot remaining single points (some twice)
                              tmp = plt.plot(dimert[idim], ert[idim], **line_styles[i]) #label=alg, )
                          plt.setp(tmp[0], markeredgecolor=plt.getp(tmp[0], 'color'))
                  else:  # to be removed
                      tmp = plt.plot(dimert, ert, **line_styles[i]) #label=alg, )
                      plt.setp(tmp[0], markeredgecolor=plt.getp(tmp[0], 'color'))
  
                  # For legend
                  # tmp = plt.plot([], [], label=alg.replace('..' + os.sep, '').strip(os.sep), **line_styles[i])
                  algorithm_name = toolsdivers.str_to_latex(toolsdivers.strip_pathname1(alg))
                  if plotting_style.in_background:
                      algorithm_name = '_' + algorithm_name
                  tmp = plt.plot([], [], label=algorithm_name[:legend_text_max_len], **line_styles[i])
                  plt.setp(tmp[0], markersize=12.,
                           markeredgecolor=plt.getp(tmp[0], 'color'))
  
                  if dimmaxevals:
                      tmp = plt.plot(dimmaxevals, maxevals, **line_styles[i])
                      plt.setp(tmp[0], markersize=20, #label=alg,
                               markeredgecolor=plt.getp(tmp[0], 'color'),
                               markeredgewidth=1,
                               markerfacecolor='None', linestyle='None')
  
                  #tmp2 = plt.plot(dimmedian, medianfes, ls='', marker='+',
                  #               markersize=30, markeredgewidth=5,
                  #               markeredgecolor=plt.getp(tmp, 'color'))[0]
                  #for i, n in enumerate(nbsucc):
                  #    plt.text(dimnbsucc[i], numpy.array(ynbsucc[i])*1.85, n,
                  #             verticalalignment='bottom',
                  #             horizontalalignment='center')
  
                  if not plotting_style.in_background:
                      handles.append(tmp)
                      sorted_algorithms = plotting_style.algorithm_list
                      styles = line_styles
  
          refalgentries = bestalg.load_reference_algorithm(testbedsettings.current_testbed.reference_algorithm_filename)
  
          if refalgentries:        
              refalgdata = []
              dimrefalg = list(df[0] for df in refalgentries if df[1] == f)
              dimrefalg.sort()
              dimrefalg2 = []
              for d in dimrefalg:
                  entry = refalgentries[(d, f)]
                  tmp = entry.detERT(target((f, d)))[0]
                  if numpy.isfinite(tmp):
                      refalgdata.append(float(tmp)/d)
                      dimrefalg2.append(d)
      
              tmp = plt.plot(dimrefalg2, refalgdata, color=refcolor, linewidth=10,
                             marker='d', markersize=25, markeredgecolor=refcolor, zorder=-1
                             #label='best 2009', 
                             )
              handles.append(tmp)
          
          if show_significance: # plot significance-stars
              xstar, ystar = [], []
              dims = sorted(pproc.dictAlgByDim(dictFunc[f]))
              for i, dim in enumerate(dims):
                  datasets = pproc.dictAlgByDim(dictFunc[f])[dim]
                  assert all([len(datasets[ialg]) == 1 for ialg in sorted_algorithms if datasets[ialg]])
                  dsetlist =  [datasets[ialg][0] for ialg in sorted_algorithms if datasets[ialg]]
                  if len(dsetlist) > 1:
                      arzp, arialg = toolsstats.significance_all_best_vs_other(dsetlist, target((f, dim)))
                      if arzp[0][1] * len(dims) < show_significance:
                          ert = dsetlist[arialg[0]].detERT(target((f, dim)))[0]
                          if ert < numpy.inf: 
                              xstar.append(dim)
                              ystar.append(ert/dim)
  
              plt.plot(xstar, ystar, '*',
                       markerfacecolor='k',  # visible over light colors
                       markeredgecolor='red',  # visible over dark colors
                       markeredgewidth=0.7,
                       markersize=styles[0]['markersize'])
          
          fontSize = getFontSize(funInfos.values())
          if f in funInfos.keys():
              plt.gca().set_title(funInfos[f], fontsize=0.9*fontSize)
  
          functions_with_legend = testbedsettings.current_testbed.functions_with_legend
          isLegend = False
          if legend:
              plotLegend(handles)
          elif f in functions_with_legend and len(sorted_algorithms) < 1e6: # 6 elements at most in the boxed legend
                  isLegend = True
  
          beautify(legend=isLegend, rightlegend=legend)
  
          # bottom labels with #instances and type of targets:
          infotext = ''
          algorithms_with_data = [a for a in dictAlg.keys() if dictAlg[a] != []]
  
          num_of_instances = []
          for alg in algorithms_with_data:
              try:
                  # display number of instances in data and used targets type:
                  if all(d.instancenumbers == (dictFunc[f][alg])[0].instancenumbers
                         for d in dictFunc[f][alg]):  # all the same?
                      num_of_instances.append(len((dictFunc[f][alg])[0].instancenumbers))
                  else:
                      for d in dictFunc[f][alg]:
                          num_of_instances.append(len(d.instancenumbers))
              except IndexError:
                  pass
          # issue a warning if number of instances is inconsistant, otherwise
          # display only the present number of instances, i.e. remove copies
          if len(set(num_of_instances)) > 1 and genericsettings.warning_level >= 5:
              warnings.warn('Number of instances inconsistent over all algorithms.')
          num_of_instances = set(num_of_instances)
          for n in num_of_instances:
              infotext += '%d, ' % n
  
          infotext = infotext.rstrip(', ')
          infotext += ' instances\n'
          infotext += 'target ' + target.label_name() + ': ' + target.label(0)
          plt.text(plt.xlim()[0], plt.ylim()[0],
                   infotext, fontsize=fontsize, horizontalalignment="left",
                   verticalalignment="bottom")
  
          save_figure(filename, dictAlg[algorithms_with_data[0]][0].algId)
  
          plt.close()
  
      htmlFile = os.path.join(output_dir, html_file_prefix + '.html')
      # generate commands in tex file:
      try:
          abc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
          alg_definitions = []
          alg_definitions_html = ''
          for i in range(len(sorted_algorithms)):
              symb = r'{%s%s}' % (color_to_latex(styles[i]['color']),
                                  marker_to_latex(styles[i]['marker']))
              symb_html = '<span style="color:%s;">%s</span>' % (styles[i]['color'], marker_to_html(styles[i]['marker']))
              
              alg_definitions.append((', ' if i > 0 else '') + '%s: %s' % (symb, '\\algorithm' + abc[i % len(abc)]))
              alg_definitions_html += (', ' if i > 0 else '') + '%s: %s' % (symb_html, toolsdivers.str_to_latex(toolsdivers.strip_pathname1(sorted_algorithms[i])))
          toolsdivers.prepend_to_file(latex_commands_file,
                  [providecolorsforlatex()]) # needed since the latest change in ACM template
          toolsdivers.prepend_to_file(latex_commands_file,
                                      [  # '\\providecommand{\\bbobppfigsftarget}{\\ensuremath{10^{%s}}}'
                                          #       % target.loglabel(0), # int(numpy.round(numpy.log10(target))),
                                          '\\providecommand{\\bbobppfigslegend}[1]{',
                                          scaling_figure_caption(),
                                          'Legend: '] + alg_definitions + ['}']
                                      )
          toolsdivers.prepend_to_file(latex_commands_file,
                                      ['\\providecommand{\\bbobECDFslegend}[1]{',
                                       ecdfs_figure_caption(), '}']
                                      )
          
          toolsdivers.replace_in_file(htmlFile, '##bbobppfigslegend##', scaling_figure_caption(True) + 'Legend: ' + alg_definitions_html)
  
          if genericsettings.verbose:
              print('Wrote commands and legend to %s' % filename)
  
          # this is obsolete (however check templates)
          filename = os.path.join(output_dir, 'ppfigs.tex')
          f = open(filename, 'w')
          f.write('% Do not modify this file: calls to post-processing software'
                  + ' will overwrite any modification.\n')
          f.write('Legend: ')
          
          for i in range(0, len(sorted_algorithms)):
              symb = r'{%s%s}' % (color_to_latex(styles[i]['color']),
                                  marker_to_latex(styles[i]['marker']))
              f.write((', ' if i > 0 else '') + '%s:%s' % (symb, writeLabels(sorted_algorithms[i])))
          f.close()    
          if genericsettings.verbose:
              print('(obsolete) Wrote legend in %s' % filename)
      except IOError:
          raise
  
  
          handles.append(tmp)
  
          if f in funInfos.keys():
              plt.gca().set_title(funInfos[f], fontsize=fontSize)
  
          beautify(rightlegend=legend)
  
          if legend:
              plotLegend(handles)
          else:
              if f in functions_with_legend:
                  toolsdivers.legend()
  
          save_figure(filename, dictAlg[algorithms_with_data[0]][0].algId)
  
          plt.close()
  
  def providecolorsforlatex():
      """ Provides the dvipsnames colors in pure LaTeX.
      
      Used when the xcolor option of the same name is not available, e.g.
      within the new ACM LaTeX templates.
      
      """
      return r"""% define some COCO/dvipsnames colors because
  % ACM style does not allow to use them directly
  \definecolor{NavyBlue}{HTML}{000080}
  \definecolor{Magenta}{HTML}{FF00FF}
  \definecolor{Orange}{HTML}{FFA500}
  \definecolor{CornflowerBlue}{HTML}{6495ED}
  \definecolor{YellowGreen}{HTML}{9ACD32}
  \definecolor{Gray}{HTML}{BEBEBE}
  \definecolor{Yellow}{HTML}{FFFF00}
  \definecolor{GreenYellow}{HTML}{ADFF2F}
  \definecolor{ForestGreen}{HTML}{228B22}
  \definecolor{Lavender}{HTML}{FFC0CB}
  \definecolor{SkyBlue}{HTML}{87CEEB}
  \definecolor{NavyBlue}{HTML}{000080}
  \definecolor{Goldenrod}{HTML}{DDF700}
  \definecolor{VioletRed}{HTML}{D02090}
  \definecolor{CornflowerBlue}{HTML}{6495ED}
  \definecolor{LimeGreen}{HTML}{32CD32}
  """
  