Add a section or exercise covering API design patterns for simplifying functions with many parameters.
Good reference example: DHI/modelskill#492 — the scatter() function has grown a long signature:
defscatter(
x: np.ndarray,
y: np.ndarray,
*,
bins: int|float=120,
quantiles: int|Sequence[float] |None=None,
fit_to_quantiles: bool=False,
show_points: bool|int|float|None=None,
show_hist: Optional[bool] =None,
show_density: Optional[bool] =None,
norm: Optional[colors.Normalize] =None,
backend: Literal["matplotlib", "plotly"] ="matplotlib",
figsize: Tuple[float, float] = (8, 8),
xlim: Optional[Tuple[float, float]] =None,
ylim: Optional[Tuple[float, float]] =None,
reg_method: str|bool="ols",
title: str="",
xlabel: str="",
ylabel: str="",
skill_table: Optional[str|Sequence[str] |Mapping[str, str] |bool] =False,
skill_scores: Mapping[str, float] |None=None,
skill_score_unit: Optional[str] ="",
ax: Optional[Axes] =None,
**kwargs,
) ->Axes:
Alternative patterns to simplify
1. Fluent interface (method chaining)
Each component gets its own method. Easy to add/remove parts.
(Comparer(x, y)
.plot()
.scatter(alpha=0.5)
.qq([0.05, 0.5, 0.75, 0.95])
# .reg_line(equation=True)
.skill_table(("n", "bias"))
).show()2. Configuration objects (dataclasses)
Group related parameters into typed config objects.
@dataclassclassScatterStyle:
bins: int=120show_points: bool=Trueshow_density: bool=Falsenorm: colors.Normalize|None=None@dataclassclassLayout:
figsize: tuple[float, float] = (8, 8)
xlim: tuple[float, float] |None=Noneylim: tuple[float, float] |None=Nonetitle: str=""xlabel: str=""ylabel: str=""scatter(x, y, style=ScatterStyle(bins=50), layout=Layout(title="My plot"))
3. Presets / named styles
Offer common configurations as named presets, with overrides.
scatter(x, y, preset="minimal") # just points + 1:1 linescatter(x, y, preset="full") # density + qq + regression + skill tablescatter(x, y, preset="presentation") # large fonts, clean layoutscatter(x, y, preset="minimal", title="Hm0") # preset + override
4. Composition of small functions
Instead of one function that does everything, provide building blocks that work with a standard Axes.
fig, ax=plt.subplots()
plot_scatter(ax, x, y, show_density=True)
plot_qq(ax, x, y, quantiles=[0.25, 0.5, 0.75])
plot_reg_line(ax, x, y)
add_skill_table(ax, x, y, metrics=["bias", "rmse"])
Each pattern has trade-offs worth discussing: discoverability, type safety, composability, backwards compatibility, learning curve.
Relevant topics: method chaining, Self return type, builder pattern, dataclasses as config, API design trade-offs.
Add a section or exercise covering API design patterns for simplifying functions with many parameters.
Good reference example: DHI/modelskill#492 — the
scatter()function has grown a long signature:Alternative patterns to simplify
1. Fluent interface (method chaining)
Each component gets its own method. Easy to add/remove parts.
2. Configuration objects (dataclasses)
Group related parameters into typed config objects.
3. Presets / named styles
Offer common configurations as named presets, with overrides.
4. Composition of small functions
Instead of one function that does everything, provide building blocks that work with a standard Axes.
Each pattern has trade-offs worth discussing: discoverability, type safety, composability, backwards compatibility, learning curve.
Relevant topics: method chaining,
Selfreturn type, builder pattern, dataclasses as config, API design trade-offs.