jktr / matplotlib-backend-kitty

show matplotlib plots directly in your kitty terminal
Creative Commons Zero v1.0 Universal
137 stars 16 forks source link

Allow setting custom facecolors for figures #8

Closed luciodaou closed 11 months ago

luciodaou commented 1 year ago

Hello. I'm having an issue where Matplotlib's facecolor options for the outside background is not working :

Situation 1 - should show white background if facecolor is not specified: image

Situation 2 - should show the color specified on facecolor, but shows grey: image

Situation 3 - Works normally without using MPL/Kitty backend: image

I found on the code a reference to this: https://github.com/jktr/matplotlib-backend-kitty/blob/d7681fe7cb6af100ad000626dca0128be2ec3f0f/matplotlib-backend-kitty/__init__.py#L55

Removing the , facecolor='#888888' option makes it work just like normal matplotlib does: No facecolor setting shows as white: image

Specified color shows correctly: image

I'm creating a PR for this change (see below).

My info:

fedora in 🌐 server in ~
❯ kitty -v
kitty 0.27.1 created by Kovid Goyal
fedora in 🌐 server in ~
❯ pip list | grep matplot
matplotlib               3.7.1
matplotlib-backend-kitty 2.1.2
fedora in 🌐 server in ~
❯ cat /etc/os-release
NAME="Fedora Linux"
VERSION="37 (Cloud Edition)"
ID=fedora
VERSION_ID=37
VERSION_CODENAME=""
PLATFORM_ID="platform:f37"
PRETTY_NAME="Fedora Linux 37 (Cloud Edition)"
...
fedora in 🌐 server in ~
❯ python -VVV
Python 3.11.2 (main, Feb  8 2023, 00:00:00) [GCC 12.2.1 20221121 (Red Hat 12.2.1-4)]
fedora in 🌐 server in ~
❯
jktr commented 1 year ago

The reason for the gray facecolor is legibility of figure labels. Using either white or black labels by default makes the labels hard to read on a terminal that uses either a light or dark color scheme, respectively. Partially transparent terminal backgrounds in combination with wallpapers complicate this further, but let's ignore that for now.

Ideally, I'd want to auto-detect a label color that has high contrast with the terminal's background color, and not touch facecolor at all. I'm not aware of a way to do this, so forcing the facecolor to a known value is a way that at least keeps the labels somewhat consistently legible across color schemes. I went with gray for that because the contrast with both the dark and light color schemes isn't too jarring.

I can't really remove the facecolor override unless there is another way to keep the charts legible across color schemes. A workaround might be detecting if face/label colors were set explicitly and skipping the overrides in that case; if we can't detect that, an envvar color setting might be reasonable instead.

Could you describe your usecase for choosing a different facecolor? That might help in evaluating possible approaches.

luciodaou commented 1 year ago

The reason for the gray facecolor is legibility of figure labels. Using either white or black labels by default makes the labels hard to read on a terminal that uses either a light or dark color scheme, respectively. Partially transparent terminal backgrounds in combination with wallpapers complicate this further, but let's ignore that for now.

I'm really not sure what you're referring to. If facecolor is not specified, matplotlib defaults to white. But the color itself doesn't matter, it's not subject to the terminal colors or opacity. So any problem with legibility would already be there with matplotlib anyway, to be fixed by who's dealing with the plot.

I use it to plot a meteorological diagram on kitty terminal. Grey facecolor makes the legibility worse, as it's meant to be white.

No facecolor specified, kitty with 0.5 opacity: image

Facecolor fixed to #888888, kitty with 0.5 opacity: image

Fixing facecolor to #888888 is just removing a feature of matplotlib that should be users' decision, and not something up to this module to fix.

joemilbourn commented 1 year ago

I came here to make the same issue and pr! Thanks @luciodaou. (and thanks @jktr for something I use almost every day).

Could you describe your usecase for choosing a different facecolor? That might help in evaluating possible approaches.

I use kitty with a black background, and plt.style.use("dark_background"), which sets the figure background to black and the foreground to light. Much nicer with black figure backgrounds - as per the style - than gray, so I end up patching __init__.py everytime.

I guess I'd argue that ensuring the charts are legible across color schemes is the user's, or the style's, problem rather than the renderer. If I ask for something labelled in black on a black background that's on me.

E.g. here's what the default and dark style looks like with the facecolor=#888888: Untitled

and here's what it looks like not setting the facecolor: Untitled

(plots generated by https://matplotlib.org/stable/gallery/style_sheets/style_sheets_reference.html tweaked to use matplotlib-backend-kitty and only two styles).

jktr commented 11 months ago

I'm really not sure what you're referring to. If facecolor is not specified, matplotlib defaults to white. But the color itself doesn't matter, it's not subject to the terminal colors or opacity. So any problem with legibility would already be there with matplotlib anyway, to be fixed by who's dealing with the plot.

I was under the impression that matplotlib defaulted to transparency, but that is incorrect, which invalidates my earlier comment about color schemes.

Reading over old commit messages, it seems I originally set both transparency and facecolor to work around scrollback behavior in an older kitty release. When that behavior was changed, I dropped the transparency workaround, but seemingly forgot to also remove the facecolor override.

Given that the defaults are sane and the original reason for the override is gone, I have no problem with removing the override.

jktr commented 11 months ago

fixed in #9