Problem
Plotly's SVG output references fonts by name only (e.g. font-family: 'My Font'); it never embeds the font bytes. When Kaleido renders that SVG to a raster or vector format, the font name is resolved against fonts available to the headless browser/OS. If the requested font is not installed system-wide, it silently falls back to a default (e.g. Times New Roman).
For PDF/EPS this is unavoidable today even with workarounds, because Kaleido loads the SVG into an <img> element and prints the page — an <img>-loaded SVG is an isolated document, so it can't see any @font-face defined on the host page.
The practical consequence: a chart authored with a brand/custom font renders correctly on the author's machine (where the font happens to be installed) but differently on CI, in containers, or on a colleague's machine.
Reproduction (current behavior)
Pick any font file (.ttf/.otf/.woff) whose family is not installed system-wide on your machine and set the two variables below. A distinctive display font such as Pacifico is a safe default on most systems:
curl -L -o font.ttf \
https://github.com/google/fonts/raw/main/ofl/pacifico/Pacifico-Regular.ttf
import asyncio
import kaleido
import plotly.graph_objects as go
FONT_PATH = "font.ttf" # a font NOT installed on your system
FAMILY = "Pacifico" # its family name
fig = go.Figure(go.Scatter(y=[1, 4, 2, 7, 5], mode="lines+markers"))
fig.update_layout(width=700, height=500, font_family=FAMILY,
title_text=f"{FAMILY} test")
async def main():
async with kaleido.Kaleido(n=1, timeout=90) as k:
await k.write_fig(fig, path="chart.pdf", opts={"format": "pdf"})
asyncio.run(main())
Inspect which font the PDF actually embedded:
from pypdf import PdfReader
fonts = set()
def visit(t, cm, tm, fd, sz):
if fd and "/BaseFont" in fd: fonts.add(str(fd["/BaseFont"]))
for p in PdfReader("chart.pdf").pages:
p.extract_text(visitor_text=visit)
print(fonts)
Observed: the embedded font is a system fallback (e.g. a Times/serif face), not FAMILY. The same chart looks different on a machine where FAMILY is installed — output is not reproducible across environments. (If you instead see FAMILY embedded, that font is installed on your machine — pick a different one.)
Desired behavior
A way to tell Kaleido to embed specific font files into the output so figures render with the intended typeface everywhere, without requiring a system font install — e.g.:
await k.write_fig(fig, path="chart.pdf",
opts={"format": "pdf", "fonts": [FONT_PATH]})
After which the PDF embeds the actual FAMILY glyphs (a subset such as AAAAAA+Pacifico-Regular) and the SVG carries an inlined base64 @font-face, making vector output self-contained.
A draft implementation is in #463.
Problem
Plotly's SVG output references fonts by name only (e.g.
font-family: 'My Font'); it never embeds the font bytes. When Kaleido renders that SVG to a raster or vector format, the font name is resolved against fonts available to the headless browser/OS. If the requested font is not installed system-wide, it silently falls back to a default (e.g. Times New Roman).For PDF/EPS this is unavoidable today even with workarounds, because Kaleido loads the SVG into an
<img>element and prints the page — an<img>-loaded SVG is an isolated document, so it can't see any@font-facedefined on the host page.The practical consequence: a chart authored with a brand/custom font renders correctly on the author's machine (where the font happens to be installed) but differently on CI, in containers, or on a colleague's machine.
Reproduction (current behavior)
Pick any font file (
.ttf/.otf/.woff) whose family is not installed system-wide on your machine and set the two variables below. A distinctive display font such as Pacifico is a safe default on most systems:Inspect which font the PDF actually embedded:
Observed: the embedded font is a system fallback (e.g. a Times/serif face), not
FAMILY. The same chart looks different on a machine whereFAMILYis installed — output is not reproducible across environments. (If you instead seeFAMILYembedded, that font is installed on your machine — pick a different one.)Desired behavior
A way to tell Kaleido to embed specific font files into the output so figures render with the intended typeface everywhere, without requiring a system font install — e.g.:
After which the PDF embeds the actual
FAMILYglyphs (a subset such asAAAAAA+Pacifico-Regular) and the SVG carries an inlined base64@font-face, making vector output self-contained.A draft implementation is in #463.