Skip to content

Allow user-defined stylesheets. #156

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

Closed
wants to merge 5 commits into from
Closed
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Users can override the napari-theme-based style
... with their own custom stylesheet. At the moment this must be called
'user.mplstyle' in the cwd.
  • Loading branch information
samcunliffe committed Jun 8, 2023
commit be3ed986bcfd458f6f06919f619aec7363ab5a67
35 changes: 29 additions & 6 deletions src/napari_matplotlib/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from pathlib import Path
from typing import List, Optional, Tuple

import matplotlib.style
import napari
from matplotlib.axes import Axes
from matplotlib.backends.backend_qtagg import (
Expand Down Expand Up @@ -41,9 +42,11 @@ def __init__(
super().__init__(parent=parent)
self.viewer = napari_viewer

has_mpl_stylesheet = self._apply_user_stylesheet_if_present()
self.canvas = FigureCanvas()

self.canvas.figure.patch.set_facecolor("none")
if not has_mpl_stylesheet:
self.canvas.figure.patch.set_facecolor("none")
self.canvas.figure.set_layout_engine("constrained")
self.toolbar = NapariNavigationToolbar(
self.canvas, parent=self
Expand All @@ -70,10 +73,16 @@ def add_single_axes(self) -> None:
The Axes is saved on the ``.axes`` attribute for later access.
"""
self.axes = self.figure.subplots()
self.apply_napari_colorscheme(self.axes)
self.apply_style(self.axes)

def apply_style(self, ax: Axes) -> None:
"""
Use the user-supplied stylesheet if present, otherwise apply the
napari-compatible colorscheme (theme-dependent) to an Axes.
"""
if self._apply_user_stylesheet_if_present():
return

def apply_napari_colorscheme(self, ax: Axes) -> None:
"""Apply napari-compatible colorscheme to an Axes."""
# get the foreground colours from current theme
theme = napari.utils.theme.get_theme(self.viewer.theme, as_dict=False)
fg_colour = theme.foreground.as_hex() # fg is a muted contrast to bg
Expand All @@ -93,6 +102,20 @@ def apply_napari_colorscheme(self, ax: Axes) -> None:
ax.tick_params(axis="x", colors=text_colour)
ax.tick_params(axis="y", colors=text_colour)

def _apply_user_stylesheet_if_present(self) -> bool:
"""
Apply the user-supplied stylesheet if present.

Returns
-------
True if the stylesheet was present and applied.
False otherwise.
"""
if (Path.cwd() / "user.mplstyle").exists():
matplotlib.style.use("./user.mplstyle")
return True
return False

def _on_theme_change(self) -> None:
"""Update MPL toolbar and axis styling when `napari.Viewer.theme` is changed.

Expand All @@ -101,7 +124,7 @@ def _on_theme_change(self) -> None:
"""
self._replace_toolbar_icons()
if self.figure.gca():
self.apply_napari_colorscheme(self.figure.gca())
self.apply_style(self.figure.gca())

def _theme_has_light_bg(self) -> bool:
"""
Expand Down Expand Up @@ -245,7 +268,7 @@ def _draw(self) -> None:
isinstance(layer, self.input_layer_types) for layer in self.layers
):
self.draw()
self.apply_napari_colorscheme(self.figure.gca())
self.apply_style(self.figure.gca())
self.canvas.draw()

def clear(self) -> None:
Expand Down