matplotlib / matplotlib

matplotlib: plotting with Python

Home Page:https://matplotlib.org/stable/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Inconsistent font settings when changing style context

utf opened this issue · comments

Bug report

Bug summary

When using style context manager to apply font styles the behaviour is not predictable. Below are two examples. Overall it seems like the styling is being defined when the axis is created, and not refreshed when the style is tweaked.

Example 1

If the axis is created outside the style context, then no font updates are applied when entering and saving the figure in the style context.

Code for reproduction

import matplotlib
import matplotlib.pyplot as plt

font_style = {'font.sans-serif': 'Bitstream Vera Sans',
              'font.size': 22}

fig, ax = plt.subplots()

with matplotlib.pyplot.style.context(font_style):
    print(matplotlib.rcParams['font.sans-serif'])
    print(matplotlib.rcParams['font.size'])

    ax.set_xlabel('test')
    ax.set_ylabel('test')
    plt.savefig('example_1.png', bbox_inches='tight')

Actual outcome

Console:

['Bitstream Vera Sans']
22.0

example_1

Expected outcome

The font size should be bigger and be Bitstream Vera Sans.

Example 2

Creating the figure in the context, then exiting the context and writing a new piece of text (using different settings) does not apply the correct font settings.

Code for reproduction

import matplotlib
import matplotlib.pyplot as plt

font_style = {'font.sans-serif': 'Bitstream Vera Sans',
              'font.size': 22}

with matplotlib.pyplot.style.context(font_style):
    fig, ax = plt.subplots()
    print(matplotlib.rcParams['font.sans-serif'])
    print(matplotlib.rcParams['font.size'])
    ax.set_xlabel('test')

print(matplotlib.rcParams['font.sans-serif'])
print(matplotlib.rcParams['font.size'])
ax.set_ylabel('test')

plt.savefig('example_2.png', bbox_inches='tight')

Actual outcome

Console;

['Bitstream Vera Sans']
22.0
['DejaVu Sans', 'Bitstream Vera Sans', 'Computer Modern Sans Serif', 'Lucida Grande', 'Verdana', 'Geneva', 'Lucid', 'Arial', 'Helvetica', 'Avant Garde', 'sans-serif']
10.0

example_2

Expected outcome

One axis label should be size 22 Bitstream Vera Sans, the other axis label should be size 10 DejaVu Sans.

Matplotlib version

  • Operating system: Bash on windows
  • Matplotlib version: 2.1.2
  • Matplotlib backend: TkAgg
  • Python version: 3.5.2

Matplotlib was installed via pip.

Some more data points: here's a little experiment on Linux Mint with Matplotlib 2.2.2 using iPython 6.1.0 with the %matplotlib magic and TkAgg backend.

mpl_context

The new font is applied correctly in the exported PNG, but not in the floating figure. Other styling (dark background, green ticks) are applied correctly. Without using the %matplotlib magic and calling plt.show() explicitly, the font displays correctly. Using matplotlib.style.use() instead of the context manager also works correctly.

Yeah, unfortunately the text object that will contain the labels is instantiated when the axes is created. set_xlabel currently doesn't go back and check rcParams to update the font properties.

I think it could be modified to check the rcParams. But we get into a lot of other issues with consistency. I think a lot of matplotlib depends on the idea that the rcParams aren't changing all the time, though the use of a context manager would seem to be-lie that.

At the very least, we need to be clearer in the documentation about what scope the context manager is meant to operate on: i.e. per-figure, per-axes, per-artist?

The use case we had in mind when encountering this was allowing the use of minimal style sheets to adjust different Axes within a tiled set of plots, e.g. as a way of tweaking font sizes and line widths where specialised plots have different needs. Should that be considered "un-matplotlib-ic"?

@ajjackson Not necessarily - just not how it works right now. When you call subplots you create all the axes, rcParams is checked, and the font properties set.

If you wanted to use gridspec and add the axes individually, my guess is some could be added in context, but I've not tested:

gs = gridspec.GridSpec(1, 2)

with matplotlib.pyplot.style.context(font_style1):
   fig.add_subplot(gs[0, 0])
with matplotlib.pyplot.style.context(font_style2):
   fig.add_subplot(gs[0, 1])

Its possible for set_xlabel to check the rcparam when its called, it just doesn't.

I'm going to close as won't fix. The current behaviour is the simplest, and controlling font properties can be done when making the labels..

It would be nice if plt.style.context or sns.axes_styles had a little note that they are broken for setting fonts.