Skip to content

Commit

Permalink
[parameter-sweep] implement using color maps for parameter sweeps
Browse files Browse the repository at this point in the history
  • Loading branch information
nikohansen committed Dec 11, 2024
1 parent 2527174 commit e4f3bc4
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 4 deletions.
6 changes: 3 additions & 3 deletions src/cocopp/compall/pprldmany.py
Original file line number Diff line number Diff line change
Expand Up @@ -830,11 +830,11 @@ def algname_to_label(algname, dirname=None):
data = dictData[alg]
except KeyError:
continue

args = dict(styles[i % len(styles)]) # kw-args passed to plot
style = styles[i % len(styles)]
args = dict(style) # kw-args passed to plot
args.setdefault('markeredgewidth', 1.0) # was: 1.5
args.setdefault('markerfacecolor', 'None') # transparent
args.setdefault('markeredgecolor', styles[i % len(styles)]['color'])
args.setdefault('markeredgecolor', style['color'])
args.setdefault('markersize', 9) # was: 12
args.setdefault('linewidth', 1)
args['markersize'] *= genericsettings.marker_size_multiplier
Expand Down
78 changes: 78 additions & 0 deletions src/cocopp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
"""

import importlib
import collections
import warnings
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colors as _colors
from . import ppfigdim
from . import genericsettings as settings, pproc, pprldistr
from . import testbedsettings as tbs
Expand Down Expand Up @@ -47,11 +50,86 @@ def config_target_values_setting(is_expensive, is_runlength_based):
settings.maxevals_fix_display = settings.xlimit_expensive
settings.runlength_based_targets = is_runlength_based or is_expensive

def map_indices_to_line_styles(names):
"""helper function for `config_line_styles`.
Check for equal names after a float number (which represents a
parameter value) and map the respective index in names to the index of
first appearence. This is not used for determining the color.
"""
nn = []
for n in names:
found = False
for i in range(len(n)):
if '0' <= n[i] <= '9' or n[i] == '.':
found = True
continue
elif found:
break
nn.append(n[i:])
res = {k: nn.index(v) for k, v in enumerate(nn)}
return res

def config_line_styles():
'''configure `genericsettings.line_styles` for a parameter sweet.
The colormap and range can be changed via the ``--parameter_sweep=``
value, the default value is ``plasma.0.9``, ``viridis`` and
``gnuplot2.0.85`` are viable alternatives.
The order of the input arguments determines the positioning in the
color map. The ``line_style_mapping`` attribute of `genericsettings`
can be used to chose the marker and line style like ``{input_position:
position_in_original_line_styles}``. When ``input_position`` is not
present, the usual marker line style combination is used matching
``input_position``.
TODO: we may want to have different color maps for different algorithms?
TODO: or we may want to keep the original symbol colors?
'''
s = settings.parameter_sweep
if not s or s in (0, '0', None, 'None', False, 'False', 'false', 'off', 'Off', 'OFF'):
return
if s in (1, '1', True, 'True', 'true', 't', 'on', 'On', 'ON'):
cvals = ['plasma..9', 'Greens_r..7', 'Greys_r..7', 'Reds_r..7'] # TODO: move to genericsettings
else:
try:
cvals = s.split(',')
except AttributeError:
warnings.warn("--parameter_sweep={0} value not recognized, you may"
"use 'on' or 'off' or a \nmatplotlib color map name, see also "
"``help(cocopp.config.config_line_styles)``.".format(s))
return
# map algorithm argument index to "true" algorithm index
mapping = settings.line_style_mapping or map_indices_to_line_styles(
settings._current_args)
def str_to_colormap(s, len_):
"""return a color iterator"""
cvals = s.split('.')
cmap = cvals[0]
c0 = float('.' + cvals[1]) if len(cvals) > 1 and len(cvals[1]) > 1 else 0
c1 = float('.' + cvals[2]) if len(cvals) > 2 else 1
return iter(_colors.to_hex(c) for c in plt.get_cmap(cmap)(
np.linspace(c0, c1, len_)))
counts = collections.Counter(mapping.values())
color_maps = [str_to_colormap(cvals[i % len(cvals)], counts[mapping[i]])
for i in mapping]

# modify color in settings.line_styles
settings._default_line_styles = [d.copy() for d in settings.line_styles] # a backup
for i, j in mapping.items():
s = settings.line_styles[i]
# s['markeredgecolor'] = s['color'] # doesn't work
s['color'] = next(color_maps[j])
for key in s.keys():
if key != 'color':
s[key] = settings.line_styles[j][key]

def config(suite_name=None):
"""called from a high level, e.g. rungeneric, to configure the lower level
modules via modifying parameter settings.
"""
config_line_styles()
config_target_values_setting(settings.isExpensive, settings.runlength_based_targets)
if suite_name:
tbs.load_current_testbed(suite_name, pproc.TargetValues)
Expand Down
9 changes: 9 additions & 0 deletions src/cocopp/genericsettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@
use_recommendations = [False]
'''use only recommendations data (.mdat files) for the respective algorithm
where the last element is recycled for the remaining algorithms'''
parameter_sweep = False
'''may be `True` or `'on'` or color map names to sweep through (versatile interface).
See also `cocopp.config.config_line_styles`.'''
line_style_mapping = {}
'''map the input argument position to a line style position, by default the identity.
This could useful to get the same style for several algorithm variants.'''

force_assertions = False # another debug flag for time-consuming assertions
in_a_hurry = 1000 # [0, 1000] lower resolution, no eps, saves 30% time
Expand Down Expand Up @@ -86,6 +92,9 @@
for a final camera-ready paper version.
"""

_current_args = None
'''arguments found in rungeneric.main, namely a list of folders
returned by `COCODataArchive.get_extended` of ``cocopp.archives.all``.'''

# single_target_pprldistr_values = (10., 1e-1, 1e-4, 1e-8) # used as default in pprldistr.plot method, on graph for each
# single_target_function_values = (1e1, 1e0, 1e-1, 1e-2, 1e-4, 1e-6, 1e-8) # one figure for each, seems not in use
Expand Down
15 changes: 14 additions & 1 deletion src/cocopp/rungeneric.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
# Used by getopt:
short_options = "hvo:"
long_options = ["help", "output-dir=", "noisy", "noise-free",
"tab-only", "fig-only", "rld-only", "no-rld-single-fcts",
"tab-only", "fig-only",
"parameter-sweep=",
"rld-only", "no-rld-single-fcts",
"verbose", "settings=", "conv",
"expensive", "runlength-based",
"los-only", "crafting-effort=", "pickle",
Expand Down Expand Up @@ -185,6 +187,13 @@ def main(argv=None):
all folder/file arguments are prepended with the given value
which must be a valid path.
--parameter-sweep=colormaps
'on' is a valid value too. Parse the algorithm name for a float
first and use the value to determine the color from a colormap.
`colormaps` can be 'plasma.0.9,viridis' indicating the map names
separated by commata and optionally the range for each map.
--in-a-hurry
takes values between 0 (default) and 1000, fast processing that
Expand Down Expand Up @@ -337,6 +346,8 @@ def main(argv=None):
genericsettings.isLogLoss = False
elif o == "--no-interactive":
genericsettings.interactive_mode = False
elif o == "--parameter-sweep":
genericsettings.parameter_sweep = a if a != '' else True
else:
is_assigned = False
if o in longoptlist or o in shortoptlist:
Expand Down Expand Up @@ -386,6 +397,8 @@ def main(argv=None):
# TODO: we would like the users input with timeout to confirm
# and otherwise raise a ValueError

genericsettings._current_args = args

update_background_algorithms(inputdir)

print(' Using %d data set%s:' % (len(args), 's' if len(args) > 1 else ''))
Expand Down

0 comments on commit e4f3bc4

Please sign in to comment.