Skip to content

Whitespace in mathtext is too large and inconsistent with LaTeX #4335

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
u55 opened this issue Apr 14, 2015 · 4 comments
Closed

Whitespace in mathtext is too large and inconsistent with LaTeX #4335

u55 opened this issue Apr 14, 2015 · 4 comments
Assignees
Milestone

Comments

@u55
Copy link
Contributor

u55 commented Apr 14, 2015

Hi matplotlib developers,

As a user quite familiar with LaTeX, I am constantly frustrated with the display size of the whitespace commands in matplotlib's mathtext mode with 'text.usetex':False. The matplotlib mathtext spacing commands are much larger than their LaTeX equivalents. Here is a minimal working example:

import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams.update({
    'text.usetex':False,
    'font.family':'sans-serif',
    'font.sans-serif':['DejaVu Sans'], # Needs a true unicode font
    'mathtext.default':'regular',
    })

def M(space):
    return "${0}$          '{1}'\n".format(space.join(8*['M']),space)

text = (
    M(r'\! ')+
    M(r'')+
    M(r'\hspace{0.1} ')+
    M(r'\, ')+
    M(r'\thinspace ')+
    M(r'\/ ')+
    M(r'\; ')+
    M(r'\ ')+
    M(r'\enspace ')+
    M(r'\quad ')+                         
    M(r'\qquad ')
    )

plt.figure(figsize=(8,3))
plt.axis('off')
plt.text(0,1,text,va='top')
plt.show()

mpl_spacing_bug

Tested with matplotlib 1.4.3, python 2.7 on Windows 7 and Linux.
The \thinspace command and the \enspace command are handled as Unicode characters, so this requires a true Unicode font, such as "DejaVu Sans", not the builtin default "Bitstream Vera Sans".

In the example shown above, the spacing between the series of "M" characters is much much bigger than expected for the commands \, and \; and \quad and \qquad. Also, the spacing should be monotonically increasing from top to bottom, but it clearly does not.
For instance, in LaTeX, the \, command is equivalent to \thinspace, and should be 0.16667em wide, but in matplotlib, \, is not thin at all, and is much larger than \thinspace. This means that \, is useless when one wants to create a truly-thin space in math mode.
Similarly, \; should be much smaller than \enspace.

@mdboom After poking around in the source code, I discovered that the default values of these mathtext lengths are defined in "mathtext.py" by this dictionary:

    _space_widths = { r'\ '      : 0.3,
                      r'\,'      : 0.4,
                      r'\;'      : 0.8,
                      r'\quad'   : 1.6,
                      r'\qquad'  : 3.2,
                      r'\!'      : -0.4,
                      r'\/'      : 0.4 }

where the dictionary values are the fractional width of the font (in "em" units).
I don't know where these numbers came from, but they are very different than the LaTeX specification, which can be found here:
http://tex.stackexchange.com/a/74354
or if you can find a copy of the "TeXbook" by Donald Knuth himself, or there are probably many other source on the web.

I propose to change this dictionary to the same values used by LaTeX:

    _space_widths = { r'\,'         : 0.16667,  # 3/18 em = 3 mu
                      r'\thinspace' : 0.16667,  # 3/18 em = 3 mu
                      r'\/'         : 0.16667,  # 3/18 em = 3 mu
                      r'\>'         : 0.22222,  # 4/18 em = 4 mu
                      r'\:'         : 0.22222,  # 4/18 em = 4 mu
                      r'\;'         : 0.27778,  # 5/18 em = 5 mu
                      r'\ '         : 0.33333,  # 6/18 em = 6 mu
                      r'\enspace'   : 0.5,      # 9/18 em = 9 mu
                      r'\quad'      : 1,        # 1 em = 18 mu
                      r'\qquad'     : 2,        # 2 em = 36 mu
                      r'\!'         : -0.16667, # -3/18 em = -3 mu
                      } 

And while, we are at it, we can add the LaTeX commands for \> and \:, and we can remove the Unicode dependency for \thinspace and \enspace by adding definitions to this dictionary.
(I don't think \/ is normally used by LaTeX in math mode, but in earlier versions of matplotlib it was defined to be equal to 0.1em, so it was originally intended to be a thin space.)
After making this change, the spacing behaves as expected:

mpl_spacing_bug2

However, I realize that this is a backwards incompatible change that will affect users out in the wild, but I think that it is worth the change to more sensible defaults, as long as it is well documented.
I imagine that lots of people, besides myself, expect matplotlib's mathtext to behave like LaTeX.

Today I discovered the undocumented \hspace{float} command in matplotlib's mathtext, that is similar to the LaTeX command by the same name (except that lengths in LaTeX have units). This provides a temporary workaround for me, but is annoying to have to use for such a common task as creating a thin space in math mode.

Thanks for the consideration.

@mdboom mdboom self-assigned this Apr 14, 2015
@mdboom
Copy link
Member

mdboom commented Apr 14, 2015

I just want to notate the possible similarity to #4333 (not exactly the same issue, but they are related).

@tacaswell
Copy link
Member

@u55 Thank you for the very detailed report!

@tacaswell tacaswell added this to the next point release milestone Apr 14, 2015
@tacaswell
Copy link
Member

@mdboom I have no idea on the time involved in this, but would it be reasonable to address this with the color overhaul (as we may have to regenerate lots of test images anyway).

mdboom added a commit to mdboom/matplotlib that referenced this issue May 4, 2015
mdboom added a commit to mdboom/matplotlib that referenced this issue May 4, 2015
Conflicts:
	lib/matplotlib/tests/test_mathtext.py
jenshnielsen added a commit that referenced this issue May 8, 2015
@tacaswell
Copy link
Member

There is a fix for this on the wrong branch, it just needs to be ported over.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants