Skip to content

Commit 4045b29

Browse files
committed
Add logo helper function
1 parent b3984d0 commit 4045b29

5 files changed

Lines changed: 67 additions & 1 deletion

File tree

src/scaffold/assets/logo_black.png

9.03 KB
Loading
8.55 KB
Loading
8.56 KB
Loading

src/scaffold/assets/logo_white.png

8.57 KB
Loading

src/scaffold/plotting.py

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
from contextlib import AbstractContextManager
22
from enum import Enum
3-
from typing import List
3+
from pathlib import Path
4+
from typing import List, TYPE_CHECKING
5+
6+
if TYPE_CHECKING:
7+
import matplotlib.pyplot as plt
8+
9+
ASSETS_DIR = Path(__file__).parent / "assets"
410

511
# Primary
612
BLACK = "#000000"
@@ -39,6 +45,15 @@ class MXM_STYLE(Enum):
3945
DARK = 2
4046

4147

48+
LOGO_MAP = {
49+
(MXM_STYLE.LIGHT, 0): ASSETS_DIR / "logo_black.png",
50+
(MXM_STYLE.LIGHT, 1): ASSETS_DIR / "logo_black.png",
51+
(MXM_STYLE.DARK, 0): ASSETS_DIR / "logo_offwhite.png",
52+
(MXM_STYLE.DARK, 1): ASSETS_DIR / "logo_offwhite.png",
53+
(MXM_STYLE.DARK, 2): ASSETS_DIR / "logo_offwhite.png",
54+
}
55+
56+
4257
def get_color_cycle(style: MXM_STYLE = MXM_STYLE.LIGHT) -> List[str]:
4358
"""Get color cycle for the chosen style.
4459
@@ -152,3 +167,54 @@ def get_mpl_context(style: MXM_STYLE = MXM_STYLE.LIGHT, variant: int = 0) -> Abs
152167
rc = get_rc_params(style, variant)
153168

154169
return plt.rc_context(rc=rc)
170+
171+
172+
def add_logo(
173+
fig: plt.Figure,
174+
style: MXM_STYLE = MXM_STYLE.LIGHT,
175+
variant: int = 0,
176+
logo_path: str | Path | None = None,
177+
position: str = "upper right",
178+
size: float = 0.08,
179+
alpha: float = 0.8,
180+
) -> None:
181+
"""Add a small logo to the corner of a matplotlib figure.
182+
183+
Args:
184+
fig: The matplotlib figure to add the logo to.
185+
style: The style, used to pick an appropriate default logo. Defaults to MXM_STYLE.LIGHT.
186+
variant: The variant of the style. Used to select a contrasting logo. Defaults to 0.
187+
logo_path: Path or URI to a custom logo image. If None, uses the default logo for the style/variant.
188+
position: Corner placement. One of "lower right", "lower left", "upper right", "upper left".
189+
size: Size of the logo as a fraction of figure height. Defaults to 0.08.
190+
alpha: Opacity of the logo. Defaults to 0.8.
191+
"""
192+
import io
193+
194+
import fsspec
195+
import matplotlib.image as mpimg
196+
from matplotlib.offsetbox import AnnotationBbox, OffsetImage
197+
198+
if logo_path is None:
199+
logo_path = str(LOGO_MAP[(style, variant)])
200+
201+
with fsspec.open(str(logo_path), "rb") as f:
202+
data = f.read()
203+
204+
img = mpimg.imread(io.BytesIO(data), format=Path(str(logo_path)).suffix.lstrip("."))
205+
206+
positions = {
207+
"lower right": (0.95, 0.05),
208+
"lower left": (0.05, 0.05),
209+
"upper right": (0.95, 0.95),
210+
"upper left": (0.05, 0.95),
211+
}
212+
xy = positions[position]
213+
214+
fig_height_px = fig.get_size_inches()[1] * fig.dpi
215+
logo_height_px = size * fig_height_px
216+
zoom = logo_height_px / img.shape[0]
217+
218+
imagebox = OffsetImage(img, zoom=zoom, alpha=alpha)
219+
ab = AnnotationBbox(imagebox, xy, xycoords="figure fraction", frameon=False)
220+
fig.add_artist(ab)

0 commit comments

Comments
 (0)