Skip to content

Commit 6d2f8e2

Browse files
feat: update default histogram colors to petroff10 (#557)
* update default histogram visualization to use petroff10 color cycle * raise matplotlib lower version bound to 3.10
1 parent 2fb77e2 commit 6d2f8e2

File tree

9 files changed

+15
-44
lines changed

9 files changed

+15
-44
lines changed

pyproject.toml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,14 @@ dependencies = [
4040
"boost_histogram>=1.0.0", # subclassing with family, 1.02 for stdev scaling fix (currently not needed)
4141
"hist>=2.5.0", # hist.intervals.poisson_interval
4242
"tabulate>=0.8.1", # multiline text
43-
"matplotlib>=3.5.0", # layout kwarg for subplots
43+
"matplotlib>=3.10.0", # petroff10 color cycle
4444
# below are direct dependencies of cabinetry, which are also included via pyhf[iminuit]
4545
"numpy",
4646
"pyyaml",
4747
"iminuit",
4848
"jsonschema",
4949
"click",
5050
"scipy",
51-
"packaging", # for version parsing
5251
]
5352

5453
[project.scripts]
@@ -162,6 +161,5 @@ module = [
162161
"iminuit",
163162
"jsonschema",
164163
"scipy.*",
165-
"packaging.*",
166164
]
167165
ignore_missing_imports = true

src/cabinetry/visualize/plot_model.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,11 @@
88
import matplotlib as mpl
99
import matplotlib.pyplot as plt
1010
import numpy as np
11-
import packaging.version
1211

1312
from cabinetry.visualize import utils
1413

1514
log = logging.getLogger(__name__)
1615

17-
# handling of matplotlib<3.6
18-
if packaging.version.parse(mpl.__version__) < packaging.version.parse("3.6"):
19-
MPL_STYLE = "seaborn-colorblind" # pragma: no cover
20-
else:
21-
MPL_STYLE = "seaborn-v0_8-colorblind"
22-
2316

2417
def data_mc(
2518
histogram_dict_list: list[dict[str, Any]],
@@ -77,7 +70,7 @@ def data_mc(
7770
mc_histograms_yields.append(h["yields"])
7871
mc_labels.append(h["label"])
7972

80-
mpl.style.use(MPL_STYLE)
73+
mpl.style.use("petroff10")
8174

8275
fig = plt.figure(figsize=(6, 6), layout="constrained")
8376
gs = fig.add_gridspec(nrows=2, ncols=1, hspace=0, height_ratios=[3, 1])
@@ -297,7 +290,7 @@ def templates(
297290
bin_width = bin_edges[1:] - bin_edges[:-1]
298291
bin_centers = 0.5 * (bin_edges[:-1] + bin_edges[1:])
299292

300-
mpl.style.use(MPL_STYLE)
293+
mpl.style.use("petroff10")
301294
fig = plt.figure(figsize=(8, 6), layout="constrained")
302295
gs = fig.add_gridspec(nrows=2, ncols=1, hspace=0, height_ratios=[3, 1])
303296
ax1 = fig.add_subplot(gs[0])

src/cabinetry/visualize/plot_result.py

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,14 @@
55
import pathlib
66

77
import matplotlib as mpl
8+
import matplotlib.layout_engine
89
import matplotlib.pyplot as plt
910
import numpy as np
10-
import packaging.version
1111

1212
from cabinetry.visualize import utils
1313

1414
log = logging.getLogger(__name__)
1515

16-
# handling of matplotlib<3.6
17-
if packaging.version.parse(mpl.__version__) < packaging.version.parse("3.6"):
18-
MPL_GEQ_36 = False # pragma: no cover
19-
MPL_STYLE = "seaborn-colorblind" # pragma: no cover
20-
else:
21-
MPL_GEQ_36 = True
22-
MPL_STYLE = "seaborn-v0_8-colorblind"
23-
2416

2517
def correlation_matrix(
2618
corr_mat: np.ndarray,
@@ -152,16 +144,11 @@ def ranking(
152144

153145
# layout to make space for legend on top
154146
leg_space = 1.0 / (num_pars + 3) + 0.03
155-
if MPL_GEQ_36:
156-
import matplotlib.layout_engine
157-
158-
layout = matplotlib.layout_engine.ConstrainedLayoutEngine(
159-
rect=[0, 0, 1.0, 1 - leg_space]
160-
)
161-
else:
162-
layout = None # pragma: no cover # layout set after figure creation instead
147+
layout = matplotlib.layout_engine.ConstrainedLayoutEngine(
148+
rect=[0, 0, 1.0, 1 - leg_space]
149+
)
163150

164-
mpl.style.use(MPL_STYLE)
151+
mpl.style.use("petroff10")
165152
fig, ax_pulls = plt.subplots(
166153
figsize=(8, 2.5 + num_pars * 0.45), dpi=100, layout=layout
167154
)
@@ -201,12 +188,12 @@ def ranking(
201188
)
202189
# pre-fit down
203190
pre_down = ax_impact.barh(
204-
y_pos, impact_prefit_down, fill=False, linewidth=1, edgecolor="C5"
191+
y_pos, impact_prefit_down, fill=False, linewidth=1, edgecolor="C9"
205192
)
206193
# post-fit up
207194
post_up = ax_impact.barh(y_pos, impact_postfit_up, color="C0")
208195
# post-fit down
209-
post_down = ax_impact.barh(y_pos, impact_postfit_down, color="C5")
196+
post_down = ax_impact.barh(y_pos, impact_postfit_down, color="C9")
210197
# nuisance parameter pulls
211198
pulls = ax_pulls.errorbar(bestfit, y_pos, xerr=uncertainty, fmt="o", color="k")
212199

@@ -257,9 +244,6 @@ def ranking(
257244
fontsize="large",
258245
)
259246

260-
if not MPL_GEQ_36:
261-
fig.tight_layout(rect=[0, 0, 1.0, 1 - leg_space]) # pragma: no cover
262-
263247
utils._save_and_close(fig, figure_path, close_figure)
264248
return fig
265249

@@ -291,7 +275,7 @@ def scan(
291275
Returns:
292276
matplotlib.figure.Figure: the likelihood scan figure
293277
"""
294-
mpl.style.use(MPL_STYLE)
278+
mpl.style.use("petroff10")
295279
fig, ax = plt.subplots(layout="constrained")
296280

297281
y_lim = max(par_nlls) * 1.2 # upper y-axis limit, 20% headroom
@@ -311,7 +295,7 @@ def scan(
311295
# Gaussian at best-fit parameter value for reference
312296
val_grid = np.linspace(par_vals[0], par_vals[-1], 100)
313297
gaussian_approx = [((par_val - par_mle) / par_unc) ** 2 for par_val in val_grid]
314-
ax.plot(val_grid, gaussian_approx, "--", color="C5", label="Gaussian approximation")
298+
ax.plot(val_grid, gaussian_approx, "--", color="C9", label="Gaussian approximation")
315299

316300
# scan results
317301
ax.plot(par_vals, par_nlls, "-", color="C0")
-3.96 KB
Loading
-3.73 KB
Loading
-3.44 KB
Loading

tests/visualize/reference/scan.png

-1001 Bytes
Loading
-8.97 KB
Loading

tests/visualize/test_visualize_plot_result.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,7 @@ def test_correlation_matrix(tmp_path):
2525
fname = tmp_path / "fig_from_return.png"
2626

2727
# adjust layout behavior, see https://github.com/matplotlib/matplotlib/issues/21742
28-
if plot_result.MPL_GEQ_36:
29-
fig.set_layout_engine(None)
30-
else:
31-
fig.set_constrained_layout(False)
28+
fig.set_layout_engine(None)
3229

3330
fig.savefig(fname)
3431
assert (
@@ -88,16 +85,15 @@ def test_ranking(tmp_path):
8885
impact_postfit_down,
8986
figure_path=fname,
9087
)
91-
# large tolerance needed here, possibly related to lack of set_tight_layout usage
9288
assert (
93-
compare_images("tests/visualize/reference/ranking.png", str(fname), 50) is None
89+
compare_images("tests/visualize/reference/ranking.png", str(fname), 0) is None
9490
)
9591

9692
# compare figure returned by function
9793
fname = tmp_path / "fig_from_return.png"
9894
fig.savefig(fname)
9995
assert (
100-
compare_images("tests/visualize/reference/ranking.png", str(fname), 50) is None
96+
compare_images("tests/visualize/reference/ranking.png", str(fname), 0) is None
10197
)
10298

10399
# do not save figure, but close it

0 commit comments

Comments
 (0)