def _get_contour_subplot( info: _SubContourInfo, reverse_scale: bool, target_name: str = "Objective Value", ) -> Tuple["Contour", "Scatter"]: x_indices = info.xaxis.indices y_indices = info.yaxis.indices x_values = [] y_values = [] for x_value, y_value in zip(info.xaxis.values, info.yaxis.values): if x_value is not None and y_value is not None: x_values.append(x_value) y_values.append(y_value) z_values = [[float("nan") for _ in range(len(info.xaxis.indices))] for _ in range(len(info.yaxis.indices))] for (x_i, y_i), z_value in info.z_values.items(): z_values[y_i][x_i] = z_value if len(x_indices) < 2 or len(y_indices) < 2: return go.Contour(), go.Scatter() contour = go.Contour( x=x_indices, y=y_indices, z=z_values, colorbar={"title": target_name}, colorscale=COLOR_SCALE, connectgaps=True, contours_coloring="heatmap", hoverinfo="none", line_smoothing=1.3, reversescale=reverse_scale, ) scatter = go.Scatter( x=x_values, y=y_values, marker={ "line": { "width": 2.0, "color": "Grey" }, "color": "black" }, mode="markers", showlegend=False, ) return contour, scatter
def _generate_contour_subplot( trials: List[FrozenTrial], x_param: str, y_param: str, reverse_scale: bool, param_values_range: Optional[Dict[str, Tuple[float, float]]] = None, target: Optional[Callable[[FrozenTrial], float]] = None, target_name: str = "Objective Value", ) -> Tuple["Contour", "Scatter"]: if param_values_range is None: param_values_range = {} x_indices = sorted(set(_get_param_values(trials, x_param))) y_indices = sorted(set(_get_param_values(trials, y_param))) if len(x_indices) < 2: _logger.warning( "Param {} unique value length is less than 2.".format(x_param)) return go.Contour(), go.Scatter() if len(y_indices) < 2: _logger.warning( "Param {} unique value length is less than 2.".format(y_param)) return go.Contour(), go.Scatter() # Padding to the plot for non-categorical params. x_range = param_values_range[x_param] if _is_numerical(trials, x_param): x_indices = [x_range[0]] + x_indices + [x_range[1]] y_range = param_values_range[y_param] if _is_numerical(trials, y_param): y_indices = [y_range[0]] + y_indices + [y_range[1]] z = [[float("nan") for _ in range(len(x_indices))] for _ in range(len(y_indices))] x_values = [] y_values = [] for trial in trials: if x_param not in trial.params or y_param not in trial.params: continue x_value = trial.params[x_param] y_value = trial.params[y_param] if not _is_numerical(trials, x_param): x_value = str(x_value) if not _is_numerical(trials, y_param): y_value = str(y_value) x_values.append(x_value) y_values.append(y_value) x_i = x_indices.index(x_value) y_i = y_indices.index(y_value) if target is None: value = trial.value else: value = target(trial) if isinstance(value, int): value = float(value) elif not isinstance(value, float): raise ValueError( f"Trial{trial.number} has COMPLETE state, but its target value is non-numeric." ) z[y_i][x_i] = value contour = go.Contour( x=x_indices, y=y_indices, z=z, colorbar={"title": target_name}, colorscale=COLOR_SCALE, connectgaps=True, contours_coloring="heatmap", hoverinfo="none", line_smoothing=1.3, reversescale=reverse_scale, ) scatter = go.Scatter( x=x_values, y=y_values, marker={ "line": { "width": 2.0, "color": "Grey" }, "color": "black" }, mode="markers", showlegend=False, ) return (contour, scatter)
def _generate_contour_subplot( trials: List[FrozenTrial], x_param: str, y_param: str, direction: StudyDirection, param_values_range: Optional[Dict[str, Tuple[float, float]]] = None, ) -> Tuple["Contour", "Scatter"]: if param_values_range is None: param_values_range = {} x_indices = sorted(set(_get_param_values(trials, x_param))) y_indices = sorted(set(_get_param_values(trials, y_param))) if len(x_indices) < 2: _logger.warning("Param {} unique value length is less than 2.".format(x_param)) return go.Contour(), go.Scatter() if len(y_indices) < 2: _logger.warning("Param {} unique value length is less than 2.".format(y_param)) return go.Contour(), go.Scatter() # Padding to the plot for non-categorical params. x_range = param_values_range[x_param] if not _is_categorical(trials, x_param): x_indices = [x_range[0]] + x_indices + [x_range[1]] y_range = param_values_range[y_param] if not _is_categorical(trials, y_param): y_indices = [y_range[0]] + y_indices + [y_range[1]] z = [[float("nan") for _ in range(len(x_indices))] for _ in range(len(y_indices))] x_values = [] y_values = [] for trial in trials: if x_param not in trial.params or y_param not in trial.params: continue x_value = trial.params[x_param] y_value = trial.params[y_param] if _is_categorical(trials, x_param): x_value = str(x_value) if _is_categorical(trials, y_param): y_value = str(y_value) x_values.append(x_value) y_values.append(y_value) x_i = x_indices.index(x_value) y_i = y_indices.index(y_value) if isinstance(trial.value, int): value = float(trial.value) elif isinstance(trial.value, float): value = trial.value else: raise ValueError( "Trial{} has COMPLETE state, but its value is non-numeric.".format(trial.number) ) z[y_i][x_i] = value # TODO(Yanase): Use reversescale argument to reverse colorscale if Plotly's bug is fixed. # If contours_coloring='heatmap' is specified, reversescale argument of go.Contour does not # work correctly. See https://github.com/pfnet/optuna/issues/606. colorscale = plotly.colors.PLOTLY_SCALES["Blues"] if direction == StudyDirection.MAXIMIZE: colorscale = [[1 - t[0], t[1]] for t in colorscale] colorscale.reverse() contour = go.Contour( x=x_indices, y=y_indices, z=z, colorbar={"title": "Objective Value"}, colorscale=colorscale, connectgaps=True, contours_coloring="heatmap", hoverinfo="none", line_smoothing=1.3, ) scatter = go.Scatter( x=x_values, y=y_values, marker={"line": {"width": 0.5, "color": "Grey"}, "color": "black"}, mode="markers", showlegend=False, ) return (contour, scatter)
def _generate_contour_subplot( trials: List[FrozenTrial], x_param: str, y_param: str, direction: StudyDirection) -> Tuple["Contour", "Scatter"]: x_indices = sorted( list({t.params[x_param] for t in trials if x_param in t.params})) y_indices = sorted( list({t.params[y_param] for t in trials if y_param in t.params})) if len(x_indices) < 2: _logger.warning( "Param {} unique value length is less than 2.".format(x_param)) return go.Contour(), go.Scatter() if len(y_indices) < 2: _logger.warning( "Param {} unique value length is less than 2.".format(y_param)) return go.Contour(), go.Scatter() z = [[float("nan") for _ in range(len(x_indices))] for _ in range(len(y_indices))] x_values = [] y_values = [] for trial in trials: if x_param not in trial.params or y_param not in trial.params: continue x_values.append(trial.params[x_param]) y_values.append(trial.params[y_param]) x_i = x_indices.index(trial.params[x_param]) y_i = y_indices.index(trial.params[y_param]) if isinstance(trial.value, int): value = float(trial.value) elif isinstance(trial.value, float): value = trial.value else: raise ValueError( "Trial{} has COMPLETE state, but its value is non-numeric.". format(trial.number)) z[y_i][x_i] = value # TODO(Yanase): Use reversescale argument to reverse colorscale if Plotly's bug is fixed. # If contours_coloring='heatmap' is specified, reversesecale argument of go.Contour does not # work correctly. See https://github.com/pfnet/optuna/issues/606. colorscale = plotly.colors.PLOTLY_SCALES["Blues"] if direction == StudyDirection.MINIMIZE: colorscale = [[1 - t[0], t[1]] for t in colorscale] colorscale.reverse() contour = go.Contour( x=x_indices, y=y_indices, z=z, colorbar={"title": "Objective Value"}, colorscale=colorscale, connectgaps=True, contours_coloring="heatmap", hoverinfo="none", line_smoothing=1.3, ) scatter = go.Scatter(x=x_values, y=y_values, marker={"color": "black"}, mode="markers", showlegend=False) return (contour, scatter)