Search code examples
pythonmatplotlibfontsstylestex

Matplotlib, usetex: Colorbar's font does not match plot's font


I have a matplotlib plot with a colorbar and can't seem to figure out how to match the fonts of the plot and the colorbar.

I try to use usetex for text handling, but it seems like only the ticks of the plot are affected, not the ticks of the colorbar. Also, I have searched for solution quite a bit, so in the following code sample, there are a few different attempts included, but the result still is a bold font. Minimum failing code sample:

import matplotlib as mpl
import matplotlib.pyplot as plt
import sys
import colorsys
import numpy as np


mpl.rc('text', usetex=True)
plt.rcParams["font.family"] = "Times New Roman"
plt.rcParams["font.weight"] = 100
plt.rcParams["axes.labelweight"] = 100
plt.rcParams["figure.titleweight"] = 100


def draw():
    colors = [colorsys.hsv_to_rgb(0.33, step /15, 1) for step in [2, 5, 8, 11, 14]]
    mymap = mpl.colors.LinearSegmentedColormap.from_list('value',colors, N=5)

    Z = [[0,0],[0,0]]
    levels = range(2,15+4,3)
    CS3 = plt.contourf(Z, levels, cmap=mymap)
    plt.clf()

    plt.figure(figsize=(20, 15))
    plt.gca().set_aspect('equal')

    cbar = plt.colorbar(CS3, ax=plt.gca(), shrink=0.5, fraction=0.5, aspect=30, pad=0.05, orientation="horizontal")

    cbar.set_ticks([1.5 + x for x in [2,5,8,11,14]])

    # attempts to make the fonts look the same
    cbar.ax.set_xticklabels([1,2,3,4,5], weight="light", fontsize=16)
    cbar.set_label("value", weight="ultralight", fontsize=32)
    plt.setp(cbar.ax.xaxis.get_ticklabels(), weight='ultralight', fontsize=16)

    for l in cbar.ax.xaxis.get_ticklabels():
        l.set_weight("light")

    plt.show()

draw()

Unfortunately, the fonts don't look the same at all. Picture:

plot font and colorbar font are different

I'm sure it's just a stupid misunderstanding of usetex on my part. Why does the usetex not seem to handle the colormap's font?

Thanks!


Solution

  • The issue here is that MPL wraps ticklabels in $ when usetex=True. This causes them to have different sizes than text that is not wrapped in $. When you force your ticks to be labeled with [1,2,3,4,5] these values are not wrapped in $, and are therefore rendered differently. I don't know the details of why this is, but I've run into the problem before myself.

    I'd recommend wrapping your colorbar ticks in $, for example:

    cbar.ax.set_xticklabels(['${}$'.format(tkval) for tkval in [1, 2, 3, 4, 5]])
    

    From there you should be able to figure out how to adjust font sizes/weights so that they match and you get what you want.