Skip to content

WIP: add DUNE style #568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/source/gallery/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Gallery
# and s != "LHCb" # we want LHCb1 or LHCb2
# ]
# the upper one contains all possible styles, needed?
allstyle = ["ATLAS", "ATLASAlt", "CMS", "LHCb1", "LHCb2", "ALICE"]
allstyle = ["ATLAS", "ATLASAlt", "CMS", "LHCb1", "LHCb2", "ALICE", "DUNE"]
allstyle = sorted(allstyle, key=lambda s: s.lower())
# allstyle = sorted(allstyle, key=lambda s: s.lower().endswith("tex"))
allstyle = sorted(allstyle, key=lambda s: s.lower().endswith("alt"))
Expand Down Expand Up @@ -64,6 +64,8 @@ Gallery
mplhep.cms.label(**kwargs)
elif "lhcb" in style.lower():
mplhep.lhcb.label(**kwargs)
elif "dune" in style.lower():
mplhep.dune.label(**kwargs)
ax.legend()
ax.set_xlabel('$m_{\mu\mu}$ [GeV]')
ax.set_ylabel('Events')
Expand Down
15 changes: 15 additions & 0 deletions docs/source/gallery/labels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ Position 0
.. image:: ../../_static/_generated/CMS/fill/pos0.png
:width: 45%

.. image:: ../../_static/_generated/DUNE/fill/pos0.png
:width: 45%

Position 1
-------------------

Expand All @@ -45,6 +48,9 @@ Position 1
.. image:: ../../_static/_generated/CMS/fill/pos1.png
:width: 45%

.. image:: ../../_static/_generated/DUNE/fill/pos1.png
:width: 45%

Position 2
-------------------

Expand All @@ -63,6 +69,9 @@ Position 2
.. image:: ../../_static/_generated/CMS/fill/pos2.png
:width: 45%

.. image:: ../../_static/_generated/DUNE/fill/pos2.png
:width: 45%

Position 3
-------------------

Expand All @@ -81,6 +90,9 @@ Position 3
.. image:: ../../_static/_generated/CMS/fill/pos3.png
:width: 45%

.. image:: ../../_static/_generated/DUNE/fill/pos3.png
:width: 45%

Position 4
-------------------

Expand All @@ -98,3 +110,6 @@ Position 4

.. image:: ../../_static/_generated/CMS/fill/pos4.png
:width: 45%

.. image:: ../../_static/_generated/DUNE/fill/pos4.png
:width: 45%
17 changes: 17 additions & 0 deletions docs/source/gallery/styles.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,20 @@ ALICE style

.. image:: ../../_static/_generated/ALICE/band/pos0.png
:width: 45%

DUNE
------------

DUNE style

.. image:: ../../_static/_generated/DUNE/fill/pos0.png
:width: 45%

.. image:: ../../_static/_generated/DUNE/step/pos0.png
:width: 45%

.. image:: ../../_static/_generated/DUNE/errorbar/pos0.png
:width: 45%

.. image:: ../../_static/_generated/DUNE/band/pos0.png
:width: 45%
3 changes: 2 additions & 1 deletion src/mplhep/__init__.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

# Get styles directly, also available within experiment helpers.
# Get helper functions
from . import alice, atlas, cms, label, lhcb, plot
from . import alice, atlas, cms, dune, label, lhcb, plot
from . import styles as style
from ._tools import Config
from ._version import version as __version__ # noqa: F401
Expand Down Expand Up @@ -58,6 +58,7 @@
"atlas",
"lhcb",
"alice",
"dune",
"plot",
"style",
"label",
Expand Down
61 changes: 61 additions & 0 deletions src/mplhep/dune.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Taken with a lot of insiration from https://github.com/DUNE/dune_plot_style
# Many thanks to the authors for their work!

from __future__ import annotations

import inspect

import matplotlib.pyplot as plt

import mplhep

from . import label as label_base
from ._compat import docstring
from .label import lumitext

# Import styles
from .styles import dune as style

__all__ = ("lumitext", "set_dune_logo_colors", "style")


@docstring.copy(label_base.exp_text)
def text(text="", **kwargs):
"""Add DUNE experiment text to a plot."""
for key, value in dict(mplhep.rcParams.text._get_kwargs()).items():
if (
value is not None
and key not in kwargs
and key in inspect.getfullargspec(label_base.exp_text).kwonlyargs
):
kwargs.setdefault(key, value)
kwargs.setdefault("italic", (False, True, False))
kwargs.setdefault("exp", "DUNE")
return label_base.exp_text(text=text, **kwargs)


@docstring.copy(label_base.exp_label)
def label(label=None, **kwargs):
"""Add DUNE experiment label to a plot."""
for key, value in dict(mplhep.rcParams.label._get_kwargs()).items():
if (
value is not None
and key not in kwargs
and key in inspect.getfullargspec(label_base.exp_label).kwonlyargs
):
kwargs.setdefault(key, value)
kwargs.setdefault("italic", (False, True, False))
if label is not None:
kwargs["label"] = label
kwargs.setdefault("exp", "DUNE")
return label_base.exp_label(**kwargs)


def set_dune_logo_colors():
"""Set the color cycler to use the DUNE logo colors (orange, blue, and yellow)."""
from cycler import cycler

# DUNE logo colors: orange, blue, yellow
dune_logo_colors = ["#D55E00", "#56B4E9", "#E69F00"]
cyc = cycler(color=dune_logo_colors)
plt.rc("axes", prop_cycle=cyc)
3 changes: 3 additions & 0 deletions src/mplhep/styles/__init__.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from .alice import ALICE
from .atlas import ATLAS, ATLASAlt, ATLASTex
from .cms import CMS, ROOT, CMSTex, ROOTTex
from .dune import DUNE, DUNETex
from .lhcb import LHCb, LHCb1, LHCb2, LHCbTex, LHCbTex1, LHCbTex2
from .plothist import PLOTHIST

Expand All @@ -22,6 +23,8 @@
"ATLASAlt",
"ATLASTex",
"CMSTex",
"DUNE",
"DUNETex",
"LHCb",
"LHCb1",
"LHCb2",
Expand Down
94 changes: 94 additions & 0 deletions src/mplhep/styles/dune.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
from __future__ import annotations

import matplotlib as mpl
from cycler import cycler

# DUNE style based on dune_plot_style package
DUNE = {
# Font configuration
"font.sans-serif": [
"Helvetica",
"Helvetica Neue",
"Nimbus Sans",
"Liberation Sans",
"Arial",
],
"font.family": "sans-serif",
"mathtext.fontset": "custom",
"mathtext.rm": "Helvetica",
"mathtext.bf": "Helvetica:bold",
"mathtext.sf": "Helvetica",
"mathtext.it": "Helvetica:italic",
"mathtext.tt": "Helvetica",
"mathtext.default": "regular",
# Figure size
"figure.figsize": (10.0, 10.0),
"figure.facecolor": "white",
# Text properties
"text.hinting_factor": 8,
"font.size": 26,
# Axes properties
"axes.facecolor": "white",
"axes.edgecolor": "black",
"axes.grid": False,
"axes.linewidth": 1.0,
"axes.labelsize": "xx-large",
"axes.titlesize": 36,
# Use Okabe-Ito colors with ordering that matches DUNE logo colors
"axes.prop_cycle": cycler(
"color",
[
"#000000",
"#D55E00",
"#56B4E9",
"#E69F00",
"#009E73",
"#CC79A7",
"#0072B2",
"#F0E442",
],
),
# Line properties
"lines.linewidth": 2.0,
# Patch properties (used for histograms)
"patch.linewidth": 1.5,
"patch.facecolor": "blue",
"patch.edgecolor": "#eeeeee",
"patch.antialiased": True,
# Image properties
"image.cmap": "cividis", # Colo(u)r Vision Deficiency friendly
# Grid properties (off by default)
"grid.color": "#b2b2b2",
"grid.linestyle": "--",
"grid.linewidth": 0.5,
# Legend properties
"legend.fontsize": 12,
"legend.frameon": False,
# Tick properties
"xtick.color": "black",
"xtick.direction": "in",
"xtick.labelsize": "x-large",
"xtick.major.size": 10,
"xtick.minor.size": 5,
"xtick.minor.visible": True,
"xtick.top": True,
"ytick.color": "black",
"ytick.direction": "in",
"ytick.labelsize": "x-large",
"ytick.major.size": 10,
"ytick.minor.size": 5,
"ytick.minor.visible": True,
"ytick.right": True,
}

# Filter extra items if needed
DUNE = {k: v for k, v in DUNE.items() if k in mpl.rcParams}

# Add a tex variant
DUNETex = {
**DUNE,
"text.usetex": True,
"text.latex.preamble": r"\usepackage{siunitx},\sisetup{detect-all}, \
\usepackage{helvet},\usepackage{sansmath}, \
\sansmath",
}
Binary file added tests/baseline/test_dune_label_loc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/baseline/test_style_dune.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/baseline/test_style_dune_logo_colors.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 78 additions & 0 deletions tests/test_dune.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from __future__ import annotations

import os
import sys

import matplotlib.pyplot as plt
import pytest
from matplotlib.testing.decorators import check_figures_equal

os.environ["RUNNING_PYTEST"] = "true"

import mplhep as hep

plt.switch_backend("Agg")


@pytest.mark.skipif(sys.platform != "linux", reason="Linux only")
@pytest.mark.mpl_image_compare(style="default", remove_text=False)
def test_style_dune():
plt.rcParams.update(plt.rcParamsDefault)

plt.style.use(hep.style.DUNE)
fig, ax = plt.subplots()
hep.dune.label(label="Preliminary")

plt.rcParams.update(plt.rcParamsDefault)
return fig


@pytest.mark.skipif(sys.platform != "linux", reason="Linux only")
@pytest.mark.mpl_image_compare(style="default", remove_text=False)
def test_style_dune_logo_colors():
plt.rcParams.update(plt.rcParamsDefault)

plt.style.use(hep.style.DUNE)
hep.dune.set_dune_logo_colors()
fig, ax = plt.subplots()
hep.dune.label(label="Preliminary")

plt.rcParams.update(plt.rcParamsDefault)
return fig


@pytest.mark.skipif(sys.platform != "linux", reason="Linux only")
@check_figures_equal(extensions=["pdf"])
def test_dune_style_variants(fig_test, fig_ref):
plt.rcParams.update(plt.rcParamsDefault)

hep.rcParams.clear()
plt.style.use(hep.style.DUNE)
fig_ref.subplots()

hep.rcParams.clear()
hep.style.use(hep.style.DUNE)
fig_test.subplots()


@pytest.mark.skipif(sys.platform != "linux", reason="Linux only")
@check_figures_equal(extensions=["pdf"])
def test_dune_style_str_alias(fig_test, fig_ref):
plt.rcParams.update(plt.rcParamsDefault)

hep.rcParams.clear()
plt.style.use(hep.style.DUNE)
fig_ref.subplots()

hep.rcParams.clear()
hep.style.use("DUNE")
fig_test.subplots()


@pytest.mark.mpl_image_compare(style="default")
def test_dune_label_loc():
fig, axs = plt.subplots(1, 4, figsize=(16, 4))
for i, ax in enumerate(axs.flatten()):
hep.dune.label(label="Preliminary", loc=i, ax=ax, lumi=50, data=True)
ax.set_title(f"loc={i}")
return fig
Loading
Loading