Latex equation in pygmt

Can pygmt use latex equations in text strings such as titles and axis labels? I don’t find relevant topic in pygmt documentation.

It’s not documented in PyGMT yet, and I’m not sure if anyone has got it to work since it is an advanced feature. The relevant docs on GMT is at 13. Using LaTeX Expressions in GMT — GMT 6.5.0 documentation though.

tried this out in pygmt, out of curiosity and for my possible future projects. Please see below.

Using LaTeX string in xlabel produced “40” for every space character, both inside and outside LaTeX math mode. This “40” must be from the octal code for the space character (32 decimal if I remember correctly)

import pygmt
fig = pygmt.Figure()
xlabel = r'@[\nabla^4 \psi - \Delta \sigma_{xx}^2@[ (MPa)'
# no spaces - no extra "40"
#xlabel = r'@[\nabla^4\psi-\Delta\sigma_{xx}^2@[(MPa)'
region = '-200/200/0/2'
proj = 'X15c'
fig.basemap(region=region, projection=proj, frame=['S', f'xaf+l"{xlabel}"'] )
fig.savefig('xlabel_latex_Figure.png', show=True)

Using the same string in clib.Session works fine, exactly as in the CLI GMT example:

from pygmt.clib import Session
with Session() as s:
    args = ['xlabel_latex_clibSession', 'png', '-C']
    s.call_module('begin', args=' '.join(args))
    xlabel = r'@[\nabla^4 \psi - \Delta \sigma_{xx}^2@[ (MPa)'
    region = '-200/200/0/2'
    proj = 'X15c'
    args = [f'-R{region}', f'-J{proj}', '-BS', f'-Bxaf+l"{xlabel}"']
    s.call_module('basemap', args=' '.join(args))
    s.call_module('end', args='show')

LaTeX and dvips must be present to generate the label, sudo apt install texlive helped on my Linux Mint. mamba install texlive-core did not fully help as dvips apparently needed to generate eps code was still missing.

1 Like

Thanks for the example @mkononets! Glad to see that LaTeX kinda worked!

Yes, we had this ‘hack’ in PyGMT to substitute space characters with \040, so that must be showing up here. Could you try re-running with PyGMT v0.12.0, since we removed that hacky workaround in Refactor all wrappers to pass an argument list to Session.call_module by seisman · Pull Request #3132 · GenericMappingTools/pygmt · GitHub, to see if the “40” still shows up?

Hmm, I’m not sure exactly how this would work, but it might involve either adding dvips somewhere to GitHub - conda-forge/texlive-core-feedstock: A conda-smithy repository for texlive-core., or adding a dvips recipe to GitHub - conda-forge/staged-recipes: A place to submit conda recipes before they become fully fledged conda-forge feedstocks. Using the system-installed texlive seems the best solution for now.

Sure! Just upgraded pygmt to 0.12.0, xlabel rendered exactly as in GMT docs, with all spaces placed as needed and "40"s gone.

import pygmt
fig = pygmt.Figure()
xlabel = r'@[\nabla^4 \psi - \Delta \sigma_{xx}^2@[ (MPa)'
region = '-200/200/0/2'
proj = 'X15c'
fig.basemap(region=region, projection=proj, frame=['S', f'xaf+l{xlabel}'])
fig.savefig('xlabel_latex_Figure.png', show=True)

NB f'xaf+l{xlabel}', no double quotes (") around {xlabel}, as these become part of the label on the plot

It might be worth mentioning that there is an alternative method for doing this, psfrag, for that you put plain text “labels” in the eps file, then include that eps file in a latex document which is processed and replaces the labels with arbitrary latex text. So that is really a rather different: the latex is done “from outside” rather than “from inside”, and it works on any eps file, not just those created with GMT. No criticism of the inside-GMT technique, but always nice to have choices :slightly_smiling_face:

Can you provide an example, replicating the x axis label above?

This psfrag approach works, but it is unnecessarily complicated. Many things needs doing for producing the same figure.png image. More below.

first pygmt code to generate a eps figure with a placeholder text for psfrag (here ‘xlabel’)

import pygmt
fig = pygmt.Figure()
xlabel = 'xlabel'
region = '-200/200/0/2'
proj = 'X15c'
fig.basemap(region=region, projection=proj, frame=['S', f'xaf+l{xlabel}'])
fig.savefig('xlabel_latex_Figure.eps', show=True)

LaTeX code to produce figure with the placeholder replaced by the LaTeX formula:

\documentclass[12pt]{article}
\usepackage{helvet}
\usepackage{psfrag}
\usepackage{graphicx}
\pagestyle{empty}

% You can run this by typing the following commands:
%latex psfrag.tex
%dvips -E psfrag.dvi

\renewcommand\familydefault{\sfdefault}
\begin{document}
  
% The syntax of the "psfrag" command is:
%\psfrag{tag}[<posn>][<psposn>][<scale>][<rot>]{replacement}
% See the file pfgguide.ps for full documentation.
  
\begin{figure}
  \psfrag{xlabel}[B][B][1][0]{$\nabla^4 \psi - \Delta \sigma_{xx}^2$ (MPa)}
  \includegraphics{xlabel_latex_Figure.eps}
\end{figure}
  
\end{document}

compile the LaTeX code:

latex psfrag.tex
dvips -E psfrag.dvi

and, finally, run gmt ps2raster to produce the png figure:

gmt ps2raster -A -Tg psfrag.ps

xlabel fonts are slightly smaller