Skip to content
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,7 @@ coverage.xml
htmlcov

# gh-pages build script output
/gh-pages
/gh-pages

# OS Files
.DS_Store
Binary file removed assets/frappe/bar.png
Binary file not shown.
Binary file removed assets/frappe/boxplot.png
Binary file not shown.
Binary file removed assets/frappe/imshow.png
Binary file not shown.
Binary file removed assets/frappe/palette.png
Binary file not shown.
Binary file removed assets/frappe/patches.png
Binary file not shown.
Binary file removed assets/frappe/plot.png
Binary file not shown.
Binary file removed assets/frappe/scatter.png
Binary file not shown.
Binary file removed assets/latte/bar.png
Binary file not shown.
Binary file removed assets/latte/boxplot.png
Binary file not shown.
Binary file removed assets/latte/imshow.png
Binary file not shown.
Binary file removed assets/latte/palette.png
Binary file not shown.
Binary file removed assets/latte/patches.png
Binary file not shown.
Binary file removed assets/latte/plot.png
Binary file not shown.
Binary file removed assets/latte/scatter.png
Binary file not shown.
Binary file removed assets/macchiato/bar.png
Binary file not shown.
Binary file removed assets/macchiato/boxplot.png
Binary file not shown.
Binary file removed assets/macchiato/imshow.png
Binary file not shown.
Binary file removed assets/macchiato/palette.png
Binary file not shown.
Binary file removed assets/macchiato/patches.png
Binary file not shown.
Binary file removed assets/macchiato/plot.png
Binary file not shown.
Binary file removed assets/macchiato/scatter.png
Binary file not shown.
Binary file removed assets/mocha/bar.png
Binary file not shown.
Binary file removed assets/mocha/boxplot.png
Binary file not shown.
Binary file removed assets/mocha/imshow.png
Binary file not shown.
Binary file removed assets/mocha/palette.png
Binary file not shown.
Binary file removed assets/mocha/patches.png
Diff not rendered.
Binary file removed assets/mocha/plot.png
Diff not rendered.
Binary file removed assets/mocha/scatter.png
Diff not rendered.
68 changes: 23 additions & 45 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
import json
import subprocess
from dataclasses import asdict
from importlib import reload
from pathlib import Path
from typing import Any, cast

import catppuccin
from catppuccin.models import HSL, RGB, Color, Flavor, FlavorColors, Palette
from example_plots import example_plots, plot_palette

HEADER = '''"""Catppuccin palette definition."""
from catppuccin.models import HSL, RGB, Color, Flavor, FlavorColors, Palette'''
Expand Down Expand Up @@ -54,7 +55,7 @@ def make_flavor(identifier: str, fields: dict[str, Any]) -> Flavor:
)


def codegen() -> str:
def palette_codegen() -> str:
"""Generate contents of `catppuccin/palette.py`."""
palette_json = load_palette_json()
palette = Palette(
Expand All @@ -72,26 +73,11 @@ def codegen() -> str:
return "\n".join(lines)


if __name__ == "__main__":
print("running codegen")
palette_path = Path.cwd() / "catppuccin" / "palette.py"
with palette_path.open("w", newline="\n") as f:
f.write(codegen())
print("formatting with ruff")
ruff_format = f"ruff format {palette_path}"
subprocess.run(ruff_format.split(), check=True, stdout=subprocess.DEVNULL)
print("palette.py generation complete")

# Generate the matplotlib styles
print("generating matplotlib styles")
from catppuccin.extras.matplotlib import CATPPUCCIN_STYLE_DIRECTORY
from catppuccin.palette import PALETTE
def generate_mpl_styles() -> None:
"""Generate the matplotlib .mplstyle files."""
template_text = (Path.cwd() / "matplotlib_template.txt").read_text()

template_text = (
CATPPUCCIN_STYLE_DIRECTORY / "_catppuccin_template.txt"
).read_text()

for key, palette in asdict(PALETTE).items():
for key, palette in asdict(catppuccin.PALETTE).items():
print(f"- {key}")
text = template_text
text = text.replace("<palette>", key)
Expand All @@ -100,34 +86,26 @@ def codegen() -> str:
f"<{color}>",
palette["colors"][color]["hex"].replace("#", ""),
)
style_path = CATPPUCCIN_STYLE_DIRECTORY / f"{key}.mplstyle"
style_path = Path(catppuccin.__file__).parent / f"{key}.mplstyle"
with style_path.open("w", newline="\n") as f:
f.write(text)
print("matplotlib styles generation complete")

# Generate matplotlib assets for the docs
import matplotlib as mpl
import matplotlib.pyplot as plt

import catppuccin # This loads the styles in matplotlib # noqa: F401

print("generating matplotlib asset images")
for palette_name in asdict(PALETTE):
print(f"- {palette_name}")
mpl.style.use(palette_name)
def main() -> None:
print("running palette codegen")
palette_path = Path.cwd() / "catppuccin" / "palette.py"
with palette_path.open("w", newline="\n") as f:
f.write(palette_codegen())
print("formatting with ruff")
ruff_format = f"ruff format {palette_path}"
subprocess.run(ruff_format.split(), check=True, stdout=subprocess.DEVNULL)
print("palette.py generation complete")

palette_path = Path.cwd() / "assets" / palette_name
palette_path.mkdir(exist_ok=True, parents=True)
print("generating matplotlib styles")
reload(catppuccin) # Reload the palette
generate_mpl_styles()
print("matplotlib styles generation complete")

# Plot palette separately
print(" - palette")
fig = plot_palette(palette_name)
fig.savefig(palette_path / "palette.png", dpi=DPI)

# Plot examples
for filename, plot_function in example_plots.items():
print(f" - {filename}")
fig = plot_function()
fig.savefig(palette_path / f"{filename}.png", dpi=DPI)
plt.close()
print("matplotlib asset image generation complete")
if __name__ == "__main__":
main()
5 changes: 1 addition & 4 deletions catppuccin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,4 @@

# Attempt to register styles and colormaps if matplotlib is available
if importlib.util.find_spec("matplotlib") is not None:
from catppuccin.extras.matplotlib import _register_colormap_list, _register_styles

_register_styles()
_register_colormap_list()
import catppuccin.extras.matplotlib # noqa: F401
142 changes: 62 additions & 80 deletions catppuccin/extras/matplotlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,106 +9,88 @@

1. Load a style, using `mpl.style.use`

```python
import catppuccin
import matplotlib as mpl
import matplotlib.pyplot as plt
```python
import catppuccin
import matplotlib.pyplot as plt

mpl.style.use(catppuccin.PALETTE.mocha.identifier)
plt.plot([0,1,2,3], [1,2,3,4])
plt.show()
```
plt.style.use(catppuccin.PALETTE.mocha.matplotlib_style)
plt.plot([0,1,2,3], [1,2,3,4])
plt.show()
```

1. Mix it with different stylesheets!

```python
import catppuccin
import matplotlib as mpl
import matplotlib.pyplot as plt
```python
import catppuccin
import matplotlib.pyplot as plt

mpl.style.use(["ggplot", catppuccin.PALETTE.mocha.identifier])
plt.plot([0,1,2,3], [1,2,3,4])
plt.show()
```
plt.style.use(["ggplot", catppuccin.PALETTE.mocha.matplotlib_style])
plt.plot([0,1,2,3], [1,2,3,4])
plt.show()
```

1. Load individual colors

```python
import matplotlib.pyplot as plt
import catppuccin
from catppuccin.extras.matplotlib import load_color
```python
import matplotlib.pyplot as plt
import catppuccin

color = load_color(catppuccin.PALETTE.latte.identifier, "peach")
plt.plot([0,1,2,3], [1,2,3,4], color=color)
plt.show()
```
plt.plot([0,1,2,3], [1,2,3,4], color=catppuccin.PALETTE.latte.colors.peach.hex)
plt.show()
```

1. Define custom colormaps

```python
import matplotlib.pyplot as plt
import numpy as np
import catppuccin
from catppuccin.extras.matplotlib import get_colormap_from_list

cmap = get_colormap_from_list(
catppuccin.PALETTE.frappe.identifier,
["red", "peach", "yellow", "green"],
)
rng = np.random.default_rng()
data = rng.integers(2, size=(30, 30))

plt.imshow(data, cmap=cmap)
plt.show()
```
"""

from __future__ import annotations

from dataclasses import asdict
from pathlib import Path
from typing import TYPE_CHECKING, cast

import matplotlib as mpl
import matplotlib.colors
import matplotlib.style
1. Just use the colormaps in your plots

from catppuccin.palette import PALETTE
```python
import matplotlib.pyplot as plt
import numpy as np
import catppuccin

if TYPE_CHECKING:
from collections.abc import Iterable
rng = np.random.default_rng()
data = rng.integers(10, size=(30, 30))

CATPPUCCIN_STYLE_DIRECTORY = Path(__file__).parent / "matplotlib_styles"
DEFAULT_COLORMAP_COLORS = ("base", "blue")
plt.imshow(data, cmap=catppuccin.PALETTE.mocha.cmap)
plt.show()
```

1. Define custom colormaps

def _register_styles() -> None:
"""Register the included stylesheets in the mpl style library."""
catppuccin_stylesheets = mpl.style.core.read_style_directory( # type: ignore [attr-defined]
CATPPUCCIN_STYLE_DIRECTORY
```python
import matplotlib.pyplot as plt
import numpy as np
import catppuccin
from matplotlib.colors import LinearSegmentedColormap

cmap = LinearSegmentedColormap.from_list(
"my_custom_palette",
[
getattr(catppuccin.PALETTE.frappe.colors, color_name).hex
for color_name in ["red", "peach", "yellow", "green"]
],
)
mpl.style.core.update_nested_dict(mpl.style.library, catppuccin_stylesheets) # type: ignore [attr-defined]
rng = np.random.default_rng()
data = rng.integers(10, size=(30, 30))

plt.imshow(data, cmap=cmap)
plt.show()
```
"""

def _register_colormap_list() -> None:
"""Register the included color maps in the `matplotlib` colormap library."""
for palette_name in asdict(PALETTE):
cmap = get_colormap_from_list(palette_name, DEFAULT_COLORMAP_COLORS)
mpl.colormaps.register(cmap=cmap, name=palette_name, force=True)
import matplotlib as mpl
import matplotlib.colors

from catppuccin.palette import PALETTE

def get_colormap_from_list(
palette_name: str,
color_names: Iterable[str],
) -> matplotlib.colors.LinearSegmentedColormap:
"""Get a `matplotlib` colormap from a list of colors for a specific palette."""
colors = [load_color(palette_name, color_name) for color_name in color_names]
return matplotlib.colors.LinearSegmentedColormap.from_list(palette_name, colors)
DEFAULT_COLORMAP_COLORS = ("blue", "teal", "yellow", "peach", "red")


def load_color(palette_name: str, color_name: str) -> str:
"""Load the color for a given palette and color name."""
return cast(
str,
PALETTE.__getattribute__(palette_name).colors.__getattribute__(color_name).hex,
# Register the included color maps in the `matplotlib` colormap library.
for _palette in PALETTE:
_cmap = matplotlib.colors.LinearSegmentedColormap.from_list(
_palette.identifier,
[
getattr(_palette.colors, color_name).hex
for color_name in ("blue", "teal", "yellow", "peach", "red")
],
)
mpl.colormaps.register(cmap=_cmap, name=_palette.identifier, force=True)
File renamed without changes.
File renamed without changes.
10 changes: 10 additions & 0 deletions catppuccin/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,16 @@ class Flavor:
colors: FlavorColors
"""@public"""

@property
def matplotlib_style(self) -> str:
"""Name of the matplotlib style associated with the flavor."""
return f"catppuccin.{self.identifier}"

@property
def cmap(self) -> str:
"""Name of the matplotlib colormap associated with the flavor."""
return self.identifier


@dataclass(frozen=True)
class Palette:
Expand Down
33 changes: 1 addition & 32 deletions example_plots.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,45 +131,14 @@ def example_imshow() -> plt.Figure: # type: ignore [name-defined]
return fig


def plot_examples(colormap_list: list[str]) -> None:
"""Plot data with associated colormap."""
rng = np.random.default_rng(SEED)
data = rng.random((30, 30))
n = len(colormap_list)
fig, axs = plt.subplots(
1, n, figsize=(n * 2 + 2, 3), constrained_layout=True, squeeze=False
)
for [ax, cmap] in zip(axs.flat, colormap_list):
psm = ax.pcolormesh(data, cmap=cmap, rasterized=True, vmin=0.0, vmax=1.0)
fig.colorbar(psm, ax=ax)
plt.show()


example_plots = {
"plot": example_plot,
"scatter": example_scatter,
"boxplot": example_boxplot,
"bar": example_bar,
"patches": example_patches,
"imshow": example_imshow,
}

if __name__ == "__main__":
palette_name = "mocha"
mpl.style.use(palette_name)
mpl.style.use(f"catppuccin.{palette_name}")
plot_palette(palette_name)
plt.show()
example_plot()
plt.show()
example_scatter()
plt.show()
example_boxplot()
plt.show()
example_bar()
plt.show()
example_patches()
plt.show()
example_imshow()
plt.show()
plot_examples(list(asdict(PALETTE).keys()))
plt.show()
File renamed without changes.
Loading