Skip to content

Commit

Permalink
Fix visuals in examples (#347)
Browse files Browse the repository at this point in the history
This PR fixes all of the visual issues that we currently have in the
examples. This includes
- Fixing deprecated mechanisms that were still being used
- Changing the format of of `__str__` representations to avoid messing
up when converting to notebook
- Adding several missing `__str__` representations
- Adding an `indent` function for indentation within `__str__`
representations.
- Adding a dedicated `to_string` function for formating
  • Loading branch information
AVHopp authored Sep 6, 2024
2 parents 99f5e9e + 646fb95 commit 9b14604
Show file tree
Hide file tree
Showing 27 changed files with 261 additions and 104 deletions.
22 changes: 9 additions & 13 deletions baybe/campaign.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
telemetry_record_value,
)
from baybe.utils.boolean import eq_dataframe
from baybe.utils.plotting import to_string


@define
Expand Down Expand Up @@ -84,19 +85,14 @@ class Campaign(SerialMixin):
"""The cached recommendations."""

def __str__(self) -> str:
start_bold = "\033[1m"
end_bold = "\033[0m"

# Get str representation of campaign fields
fields_to_print = [self.searchspace, self.objective, self.recommender]
fields_str = "\n\n".join(str(x) for x in fields_to_print)

# Put all relevant attributes of the campaign in one string
campaign_str = f"""{start_bold}Campaign{end_bold}
\n{start_bold}Meta Data{end_bold}\nBatches Done: {self.n_batches_done}
\rFits Done: {self.n_fits_done}\n\n{fields_str}\n"""

return campaign_str.replace("\n", "\n ").replace("\r", "\r ")
metadata_fields = [
to_string("Batches done", self.n_batches_done, single_line=True),
to_string("Fits done", self.n_fits_done, single_line=True),
]
metadata = to_string("Meta Data", *metadata_fields)
fields = [metadata, self.searchspace, self.objective, self.recommender]

return to_string(self.__class__.__name__, *fields)

@property
def measurements(self) -> pd.DataFrame:
Expand Down
16 changes: 8 additions & 8 deletions baybe/objectives/desirability.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
from baybe.targets.base import Target
from baybe.targets.numerical import NumericalTarget
from baybe.utils.basic import to_tuple
from baybe.utils.dataframe import pretty_print_df
from baybe.utils.numerical import geom_mean
from baybe.utils.plotting import to_string
from baybe.utils.validation import finite_float


Expand Down Expand Up @@ -122,19 +124,17 @@ def _normalized_weights(self) -> np.ndarray:
return np.asarray(self.weights) / np.sum(self.weights)

def __str__(self) -> str:
start_bold = "\033[1m"
end_bold = "\033[0m"

targets_list = [target.summary() for target in self.targets]
targets_df = pd.DataFrame(targets_list)
targets_df["Weight"] = self.weights

objective_str = f"""{start_bold}Objective{end_bold}
\n{start_bold}Type: {end_bold}{self.__class__.__name__}
\n{start_bold}Targets {end_bold}\n{targets_df}
\n{start_bold}Scalarizer: {end_bold}{self.scalarizer.name}"""
fields = [
to_string("Type", self.__class__.__name__, single_line=True),
to_string("Targets", pretty_print_df(targets_df)),
to_string("Scalarizer", self.scalarizer.name, single_line=True),
]

return objective_str.replace("\n", "\n ")
return to_string("Objective", *fields)

def transform(self, data: pd.DataFrame) -> pd.DataFrame: # noqa: D102
# See base class.
Expand Down
14 changes: 7 additions & 7 deletions baybe/objectives/single.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from baybe.objectives.base import Objective
from baybe.targets.base import Target
from baybe.utils.dataframe import pretty_print_df
from baybe.utils.plotting import to_string


@define(frozen=True, slots=False)
Expand All @@ -16,17 +18,15 @@ class SingleTargetObjective(Objective):
"""The single target considered by the objective."""

def __str__(self) -> str:
start_bold = "\033[1m"
end_bold = "\033[0m"

targets_list = [target.summary() for target in self.targets]
targets_df = pd.DataFrame(targets_list)

objective_str = f"""{start_bold}Objective{end_bold}
\n{start_bold}Type: {end_bold}{self.__class__.__name__}
\n{start_bold}Targets {end_bold}\n{targets_df}"""
fields = [
to_string("Type", self.__class__.__name__, single_line=True),
to_string("Targets", pretty_print_df(targets_df)),
]

return objective_str.replace("\n", "\n ")
return to_string("Objective", *fields)

@property
def targets(self) -> tuple[Target, ...]: # noqa: D102
Expand Down
4 changes: 2 additions & 2 deletions baybe/parameters/numerical.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

@define(frozen=True, slots=False)
class NumericalDiscreteParameter(DiscreteParameter):
"""Parameter class for discrete numerical parameters (a.k.a. setpoints)."""
"""Class for discrete numerical parameters (a.k.a. setpoints)."""

# class variables
is_numerical: ClassVar[bool] = True
Expand Down Expand Up @@ -100,7 +100,7 @@ def is_in_range(self, item: float) -> bool: # noqa: D102

@define(frozen=True, slots=False)
class NumericalContinuousParameter(ContinuousParameter):
"""Parameter class for continuous numerical parameters."""
"""Class for continuous numerical parameters."""

# class variables
is_numerical: ClassVar[bool] = True
Expand Down
22 changes: 22 additions & 0 deletions baybe/recommenders/meta/sequential.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
block_serialization_hook,
converter,
)
from baybe.utils.plotting import to_string


@define
Expand Down Expand Up @@ -64,6 +65,14 @@ def select_recommender( # noqa: D102
else self.initial_recommender
)

def __str__(self) -> str:
fields = [
to_string("Initial recommender", self.initial_recommender),
to_string("Recommender", self.recommender),
to_string("Switch after", self.switch_after, single_line=True),
]
return to_string(self.__class__.__name__, *fields)


@define
class SequentialMetaRecommender(MetaRecommender):
Expand Down Expand Up @@ -164,6 +173,13 @@ def select_recommender( # noqa: D102

return recommender

def __str__(self) -> str:
fields = [
to_string("Recommenders", self.recommenders),
to_string("Mode", self.mode, single_line=True),
]
return to_string(self.__class__.__name__, *fields)


@define
class StreamingSequentialMetaRecommender(MetaRecommender):
Expand Down Expand Up @@ -242,6 +258,12 @@ def select_recommender( # noqa: D102

return self._last_recommender # type: ignore[return-value]

def __str__(self) -> str:
fields = [
to_string("Recommenders", self.recommenders),
]
return to_string(self.__class__.__name__, *fields)


# The recommender iterable cannot be serialized
converter.register_unstructure_hook(
Expand Down
18 changes: 18 additions & 0 deletions baybe/recommenders/pure/bayesian/botorch.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
SubspaceDiscrete,
)
from baybe.utils.dataframe import to_tensor
from baybe.utils.plotting import to_string
from baybe.utils.sampling_algorithms import (
DiscreteSamplingMethod,
sample_numerical_df,
Expand Down Expand Up @@ -295,3 +296,20 @@ def _recommend_hybrid(
rec_exp = pd.concat([rec_disc_exp, rec_cont_exp], axis=1)

return rec_exp

def __str__(self) -> str:
fields = [
to_string("Surrogate", self.surrogate_model),
to_string(
"Acquisition function", self.acquisition_function, single_line=True
),
to_string("Compatibility", self.compatibility, single_line=True),
to_string(
"Sequential continuous", self.sequential_continuous, single_line=True
),
to_string("Hybrid sampler", self.hybrid_sampler, single_line=True),
to_string(
"Sampling percentage", self.sampling_percentage, single_line=True
),
]
return to_string(self.__class__.__name__, *fields)
13 changes: 13 additions & 0 deletions baybe/recommenders/pure/nonpredictive/clustering.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from baybe.recommenders.pure.nonpredictive.base import NonPredictiveRecommender
from baybe.searchspace import SearchSpaceType, SubspaceDiscrete
from baybe.utils.plotting import to_string


@define
Expand Down Expand Up @@ -125,6 +126,18 @@ def _recommend_discrete(
# Convert positional indices into DataFrame indices and return result
return candidates_comp.index[selection]

def __str__(self) -> str:
fields = [
to_string("Compatibility", self.compatibility, single_line=True),
to_string(
"Name of clustering parameter",
self.model_cluster_num_parameter_name,
single_line=True,
),
to_string("Model parameters", self.model_params, single_line=True),
]
return to_string(self.__class__.__name__, *fields)


@define
class PAMClusteringRecommender(SKLearnClusteringRecommender):
Expand Down
9 changes: 9 additions & 0 deletions baybe/recommenders/pure/nonpredictive/sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from baybe.recommenders.pure.nonpredictive.base import NonPredictiveRecommender
from baybe.searchspace import SearchSpace, SearchSpaceType, SubspaceDiscrete
from baybe.utils.plotting import to_string
from baybe.utils.sampling_algorithms import farthest_point_sampling


Expand Down Expand Up @@ -45,6 +46,10 @@ def _recommend_hybrid(
cont_random.index = disc_random.index
return pd.concat([disc_random, cont_random], axis=1)

def __str__(self) -> str:
fields = [to_string("Compatibility", self.compatibility, single_line=True)]
return to_string(self.__class__.__name__, *fields)


class FPSRecommender(NonPredictiveRecommender):
"""An initial recommender that selects candidates via Farthest Point Sampling."""
Expand All @@ -70,3 +75,7 @@ def _recommend_discrete(
candidates_scaled = np.ascontiguousarray(scaler.transform(candidates_comp))
ilocs = farthest_point_sampling(candidates_scaled, batch_size)
return candidates_comp.index[ilocs]

def __str__(self) -> str:
fields = [to_string("Compatibility", self.compatibility, single_line=True)]
return to_string(self.__class__.__name__, *fields)
31 changes: 13 additions & 18 deletions baybe/searchspace/continuous.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
from baybe.serialization import SerialMixin, converter, select_constructor_hook
from baybe.utils.basic import to_tuple
from baybe.utils.dataframe import pretty_print_df
from baybe.utils.plotting import to_string

if TYPE_CHECKING:
from baybe.searchspace.core import SearchSpace
Expand Down Expand Up @@ -71,9 +72,6 @@ def __str__(self) -> str:
if self.is_empty:
return ""

start_bold = "\033[1m"
end_bold = "\033[0m"

# Convert the lists to dataFrames to be able to use pretty_printing
param_list = [param.summary() for param in self.parameters]
eq_constraints_list = [constr.summary() for constr in self.constraints_lin_eq]
Expand All @@ -84,21 +82,18 @@ def __str__(self) -> str:
constr.summary() for constr in self.constraints_nonlin
]
param_df = pd.DataFrame(param_list)
lin_eq_constr_df = pd.DataFrame(eq_constraints_list)
lin_ineq_constr_df = pd.DataFrame(ineq_constraints_list)
nonlinear_constr_df = pd.DataFrame(nonlin_constraints_list)

# Put all attributes of the continuous class in one string
continuous_str = f"""{start_bold}Continuous Search Space{end_bold}
\n{start_bold}Continuous Parameters{end_bold}\n{pretty_print_df(param_df)}
\n{start_bold}List of Linear Equality Constraints{end_bold}
\r{pretty_print_df(lin_eq_constr_df)}
\n{start_bold}List of Linear Inequality Constraints{end_bold}
\r{pretty_print_df(lin_ineq_constr_df)}
\n{start_bold}List of Nonlinear Constraints{end_bold}
\r{pretty_print_df(nonlinear_constr_df)}"""

return continuous_str.replace("\n", "\n ").replace("\r", "\r ")
lin_eq_df = pd.DataFrame(eq_constraints_list)
lin_ineq_df = pd.DataFrame(ineq_constraints_list)
nonlinear_df = pd.DataFrame(nonlin_constraints_list)

fields = [
to_string("Continuous Parameters", pretty_print_df(param_df)),
to_string("Linear Equality Constraints", pretty_print_df(lin_eq_df)),
to_string("Linear Inequality Constraints", pretty_print_df(lin_ineq_df)),
to_string("Non-linear Constraints", pretty_print_df(nonlinear_df)),
]

return to_string(self.__class__.__name__, *fields)

@property
def constraints_cardinality(self) -> tuple[ContinuousCardinalityConstraint, ...]:
Expand Down
22 changes: 9 additions & 13 deletions baybe/searchspace/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from baybe.searchspace.validation import validate_parameters
from baybe.serialization import SerialMixin, converter, select_constructor_hook
from baybe.telemetry import TELEM_LABELS, telemetry_record_value
from baybe.utils.plotting import to_string


class SearchSpaceType(Enum):
Expand Down Expand Up @@ -66,19 +67,14 @@ class SearchSpace(SerialMixin):
"""The (potentially empty) continuous subspace of the overall search space."""

def __str__(self) -> str:
start_bold = "\033[1m"
end_bold = "\033[0m"
head_str = f"""{start_bold}Search Space{end_bold}
\n{start_bold}Search Space Type: {end_bold}{self.type.name}"""

# Check the sub space size to avoid adding unwanted break lines
# if the sub space is empty
discrete_str = f"\n\n{self.discrete}" if not self.discrete.is_empty else ""
continuous_str = (
f"\n\n{self.continuous}" if not self.continuous.is_empty else ""
)
searchspace_str = f"{head_str}{discrete_str}{continuous_str}"
return searchspace_str.replace("\n", "\n ").replace("\r", "\r ")
fields = [
to_string("Search Space Type", self.type.name, single_line=True),
]
if not self.discrete.is_empty:
fields.append(str(self.discrete))
if not self.continuous.is_empty:
fields.append(str(self.continuous))
return to_string(self.__class__.__name__, *fields)

def __attrs_post_init__(self):
"""Perform validation and record telemetry values."""
Expand Down
Loading

0 comments on commit 9b14604

Please sign in to comment.