Skip to content

Installing Nimbus Roman fonts on Linux

Randy McDermott edited this page Dec 4, 2025 · 1 revision

Standardizing Serif Fonts for Matplotlib on RHEL 9

This document explains how to configure Matplotlib on RHEL 9 so that PDF output uses Times-style Type 1 PostScript core fonts through the system-provided URW Base35 font package. This produces compact PDFs with consistent serif rendering (Nimbus Roman) across all users, without embedding large TrueType fonts.


1. Check Whether Nimbus Roman Is Present

Run the following:

fc-list : family | grep -i "nimbus"

You should see entries such as:

Nimbus Roman
Nimbus Sans
Nimbus Mono PS

If Nimbus Roman appears, continue to Step 4.


2. Install URW Base35 Fonts (if missing)

Install the font package:

sudo dnf install urw-base35-fonts

Verify the font files exist:

ls /usr/share/fonts/urw-base35 | grep -i nimbusroman

Look for files like:

NimbusRoman-Regular.otf
NimbusRoman-Italic.otf
NimbusRoman-Bold.otf
NimbusRoman-BoldItalic.otf

3. Rebuild Fontconfig Cache

sudo fc-cache -f -v

This ensures new fonts are visible to applications using Fontconfig (including Matplotlib).


4. Confirm Nimbus Roman via Fontconfig and Matplotlib

Check again via Fontconfig:

fc-list : family | grep -i nimbus

Then verify through Matplotlib:

python3 - <<EOF
import matplotlib.font_manager as fm
families = sorted({f.name for f in fm.fontManager.ttflist})
print([f for f in families if "Nimbus" in f])
EOF

You should see something like:

['Nimbus Roman', 'Nimbus Sans', 'Nimbus Mono PS']

Also check font resolution:

python3 - <<EOF
from matplotlib.font_manager import findfont
print(findfont("Nimbus Roman"))
EOF

Expected path example:

/usr/share/fonts/urw-base35/NimbusRoman-Regular.otf

5. Clear Matplotlib Font Caches (per user)

Each user must run:

rm -f ~/.cache/matplotlib/fontlist-*.json
rm -rf ~/.cache/matplotlib/tex.cache

Caches regenerate automatically on next Matplotlib use.


6. Required Matplotlib Runtime Settings

Add the following before creating any figures (or just use configure_fds_fonts() from fdsplotlib):

plt.rcParams.update({
    "pdf.use14corefonts": True,
    "text.usetex": False,

    "font.family": "serif",
    "font.serif": [
        "Nimbus Roman",
        "Times",
        "Times New Roman",
        "serif",
    ],

    "mathtext.fontset": "custom",
    "mathtext.rm":  "Nimbus Roman",
    "mathtext.it":  "Nimbus Roman:italic",
    "mathtext.bf":  "Nimbus Roman:bold",
    "mathtext.cal": "Nimbus Roman:italic",
    "mathtext.tt":  "Courier",
    "mathtext.default": "rm",

    "axes.unicode_minus": False,
    "pdf.compression": 9,
})

Results:

  • serif text uses Nimbus Roman (Times-style)
  • PDF uses core Type 1 fonts (Times/Helvetica/Courier)
  • No embedded TTF fonts → tiny PDF sizes
  • math text inherits Nimbus Roman styling

7. Validate Correct Font Output

Create a test PDF:

python3 - <<EOF
import matplotlib.pyplot as plt
plt.text(0.5, 0.5, r"$\\nabla \\cdot \\mathbf{u} = 0$", fontsize=20)
plt.savefig("font_check.pdf")
EOF

List fonts used:

pdffonts font_check.pdf

Expected result:

Times-Roman      Type 1  (not embedded)
Times-Bold       Type 1  (not embedded)
Courier          Type 1  (not embedded)

Type 3 math paths may appear, which is normal.
No large embedded TTF entries should be present.


8. Why Nimbus Roman

  • Installed from official RHEL repos
  • Metrics-compatible with Times Roman
  • Legally redistributable
  • Works correctly with pdf.use14corefonts=True
  • Ensures consistent output for all cluster users
  • Produces compact PDFs ideal for publications

Summary Table

Step Action
1 Confirm Nimbus Roman exists
2 Install urw-base35-fonts if needed
3 Run sudo fc-cache -f -v
4 Verify via Fontconfig and Matplotlib
5 Clear per-user Matplotlib cache
6 Apply the provided rcParams
7 Confirm fonts using pdffonts
8 Adopt Nimbus Roman as Times replacement

Once complete, all users will generate consistent, Times-style serif text in Matplotlib PDFs on RHEL 9 without embedding large TrueType fonts.

Clone this wiki locally