Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Bug]: text.usetex Vs. DateFormatter #22350

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

Open
leocirto opened this issue Jan 29, 2022 · 4 comments · Fixed by #22361
Open

[Bug]: text.usetex Vs. DateFormatter #22350

leocirto opened this issue Jan 29, 2022 · 4 comments · Fixed by #22361

Comments

@leocirto
Copy link

leocirto commented Jan 29, 2022

Bug summary

When I set rcParams['text.usetex'] = True, I can't skip line in date format.

For example, I can't use DateFormatter('%d/%m\n%Y').

Removing the skip line \n it works: '%d/%m\n%Y' --> '%d/%m/%Y'.

It was working before. It's stopped working since my last update/upgrade of Anaconda.

Code for reproduction

import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.dates as dates

mpl.rcParams['axes.labelsize'] = 15
mpl.rcParams['figure.figsize'] = [12, 3]

mpl.rcParams['text.usetex']   = True
# mpl.rcParams['text.usetex']  = False

FMT = dates.DateFormatter('%d/%m\n%Y')
# FMT = dates.DateFormatter('%d/%m/%Y')
plt.axes().xaxis.set_major_formatter( FMT )

plt.show()

Actual outcome

---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/texmanager.py in _run_checked_subprocess(self, command, tex, cwd)
    232         try:
--> 233             report = subprocess.check_output(
    234                 command, cwd=cwd if cwd is not None else self.texcache,

~/BIN/ANACONDA3_2021.11/lib/python3.9/subprocess.py in check_output(timeout, *popenargs, **kwargs)
    423 
--> 424     return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
    425                **kwargs).stdout

~/BIN/ANACONDA3_2021.11/lib/python3.9/subprocess.py in run(input, capture_output, timeout, check, *popenargs, **kwargs)
    527         if check and retcode:
--> 528             raise CalledProcessError(retcode, process.args,
    529                                      output=stdout, stderr=stderr)

CalledProcessError: Command '['latex', '-interaction=nonstopmode', '--halt-on-error', '../09efec18b9a3c1b4d23927d49f15f25f.tex']' returned non-zero exit status 1.

The above exception was the direct cause of the following exception:

RuntimeError                              Traceback (most recent call last)
~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/IPython/core/formatters.py in __call__(self, obj)
    339                 pass
    340             else:
--> 341                 return printer(obj)
    342             # Finally look for special method names
    343             method = get_real_method(obj, self.print_method)

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/IPython/core/pylabtools.py in print_figure(fig, fmt, bbox_inches, base64, **kwargs)
    149         FigureCanvasBase(fig)
    150 
--> 151     fig.canvas.print_figure(bytes_io, **kw)
    152     data = bytes_io.getvalue()
    153     if fmt == 'svg':

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/backend_bases.py in print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
   2288                 )
   2289                 with getattr(renderer, "_draw_disabled", nullcontext)():
-> 2290                     self.figure.draw(renderer)
   2291 
   2292             if bbox_inches:

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer, *args, **kwargs)
     71     @wraps(draw)
     72     def draw_wrapper(artist, renderer, *args, **kwargs):
---> 73         result = draw(artist, renderer, *args, **kwargs)
     74         if renderer._rasterizing:
     75             renderer.stop_rasterizing()

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer)
     48                 renderer.start_filter()
     49 
---> 50             return draw(artist, renderer)
     51         finally:
     52             if artist.get_agg_filter() is not None:

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/figure.py in draw(self, renderer)
   2801 
   2802             self.patch.draw(renderer)
-> 2803             mimage._draw_list_compositing_images(
   2804                 renderer, self, artists, self.suppressComposite)
   2805 

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    130     if not_composite or not has_images:
    131         for a in artists:
--> 132             a.draw(renderer)
    133     else:
    134         # Composite any adjacent images together

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer)
     48                 renderer.start_filter()
     49 
---> 50             return draw(artist, renderer)
     51         finally:
     52             if artist.get_agg_filter() is not None:

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/axes/_base.py in draw(self, renderer)
   3080             renderer.stop_rasterizing()
   3081 
-> 3082         mimage._draw_list_compositing_images(
   3083             renderer, self, artists, self.figure.suppressComposite)
   3084 

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/image.py in _draw_list_compositing_images(renderer, parent, artists, suppress_composite)
    130     if not_composite or not has_images:
    131         for a in artists:
--> 132             a.draw(renderer)
    133     else:
    134         # Composite any adjacent images together

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/artist.py in draw_wrapper(artist, renderer)
     48                 renderer.start_filter()
     49 
---> 50             return draw(artist, renderer)
     51         finally:
     52             if artist.get_agg_filter() is not None:

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/axis.py in draw(self, renderer, *args, **kwargs)
   1157 
   1158         ticks_to_draw = self._update_ticks()
-> 1159         ticklabelBoxes, ticklabelBoxes2 = self._get_tick_bboxes(ticks_to_draw,
   1160                                                                 renderer)
   1161 

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/axis.py in _get_tick_bboxes(self, ticks, renderer)
   1083     def _get_tick_bboxes(self, ticks, renderer):
   1084         """Return lists of bboxes for ticks' label1's and label2's."""
-> 1085         return ([tick.label1.get_window_extent(renderer)
   1086                  for tick in ticks if tick.label1.get_visible()],
   1087                 [tick.label2.get_window_extent(renderer)

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/axis.py in <listcomp>(.0)
   1083     def _get_tick_bboxes(self, ticks, renderer):
   1084         """Return lists of bboxes for ticks' label1's and label2's."""
-> 1085         return ([tick.label1.get_window_extent(renderer)
   1086                  for tick in ticks if tick.label1.get_visible()],
   1087                 [tick.label2.get_window_extent(renderer)

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/text.py in get_window_extent(self, renderer, dpi)
    908 
    909         with cbook._setattr_cm(self.figure, dpi=dpi):
--> 910             bbox, info, descent = self._get_layout(self._renderer)
    911             x, y = self.get_unitless_position()
    912             x, y = self.get_transform().transform((x, y))

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/text.py in _get_layout(self, renderer)
    315             clean_line, ismath = self._preprocess_math(line)
    316             if clean_line:
--> 317                 w, h, d = renderer.get_text_width_height_descent(
    318                     clean_line, self._fontproperties, ismath=ismath)
    319             else:

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/backends/backend_agg.py in get_text_width_height_descent(self, s, prop, ismath)
    257             texmanager = self.get_texmanager()
    258             fontsize = prop.get_size_in_points()
--> 259             w, h, d = texmanager.get_text_width_height_descent(
    260                 s, fontsize, renderer=self)
    261             return w, h, d

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/texmanager.py in get_text_width_height_descent(self, tex, fontsize, renderer)
    333         if tex.strip() == '':
    334             return 0, 0, 0
--> 335         dvifile = self.make_dvi(tex, fontsize)
    336         dpi_fraction = renderer.points_to_pixels(1.) if renderer else 1
    337         with dviread.Dvi(dvifile, 72 * dpi_fraction) as dvi:

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/texmanager.py in make_dvi(self, tex, fontsize)
    269             # not support.)
    270             with TemporaryDirectory(dir=Path(dvifile).parent) as tmpdir:
--> 271                 self._run_checked_subprocess(
    272                     ["latex", "-interaction=nonstopmode", "--halt-on-error",
    273                      f"../{texfile.name}"], tex, cwd=tmpdir)

~/BIN/ANACONDA3_2021.11/lib/python3.9/site-packages/matplotlib/texmanager.py in _run_checked_subprocess(self, command, tex, cwd)
    239                 'found'.format(command[0])) from exc
    240         except subprocess.CalledProcessError as exc:
--> 241             raise RuntimeError(
    242                 '{prog} was not able to process the following string:\n'
    243                 '{tex!r}\n\n'

RuntimeError: latex was not able to process the following string:
b'$\\\\mathdefault{01/01'

Here is the full report generated by latex:
This is pdfTeX, Version 3.141592653-2.6-1.40.22 (TeX Live 2021/TeX Live for SUSE Linux) (preloaded format=latex)
 restricted \write18 enabled.
entering extended mode
(../09efec18b9a3c1b4d23927d49f15f25f.tex
LaTeX2e <2020-10-01> patch level 4
L3 programming layer <2021-02-18> (/usr/share/texmf/tex/latex/base/article.cls
Document Class: article 2020/04/10 v1.4m Standard LaTeX document class
(/usr/share/texmf/tex/latex/base/size10.clo))
(/usr/share/texmf/tex/latex/type1cm/type1cm.sty)
(/usr/share/texmf/tex/latex/cm-super/type1ec.sty
(/usr/share/texmf/tex/latex/base/t1cmr.fd))
(/usr/share/texmf/tex/latex/base/inputenc.sty)
(/usr/share/texmf/tex/latex/geometry/geometry.sty
(/usr/share/texmf/tex/latex/graphics/keyval.sty)
(/usr/share/texmf/tex/generic/iftex/ifvtex.sty
(/usr/share/texmf/tex/generic/iftex/iftex.sty)))
(/usr/share/texmf/tex/latex/underscore/underscore.sty)
(/usr/share/texmf/tex/latex/base/textcomp.sty)
(/usr/share/texmf/tex/latex/l3backend/l3backend-dvips.def)
No file 09efec18b9a3c1b4d23927d49f15f25f.aux.
*geometry* driver: auto-detecting
*geometry* detected driver: dvips
! Missing $ inserted.
<inserted text> 
                $
l.19 \end{document}
                   
No pages of output.
Transcript written on 09efec18b9a3c1b4d23927d49f15f25f.log.

Expected outcome

image

If I set rcParams['text.usetex'] = True, I have to change the data format:

image

Additional information

Has this worked in earlier versions?
Yes.

Do you know why this bug is happening?
I couldn't find the LOG file cited in the Actual outcome (pasted above, the last line).

I mean, I couldn't find this file: Transcript written on 09efec18b9a3c1b4d23927d49f15f25f.log.

However I managed to find a TEX file with the same name into '/home/.cache/matplotlib/tex.cache/'

The contents of this TEX file are (I think it may help):

\documentclass{article}
\newcommand{\mathdefault}[1]{#1}
\usepackage{type1cm}
\usepackage{type1ec}
\usepackage[utf8]{inputenc}
\DeclareUnicodeCharacter{2212}{\ensuremath{-}}
\usepackage[papersize=72in, margin=1in]{geometry}

\makeatletter\@ifpackageloaded{underscore}{}{\usepackage[strings]{underscore}}\makeatother
\makeatletter\@ifpackageloaded{textcomp}{}{\usepackage{textcomp}}\makeatother
\pagestyle{empty}
\begin{document}
% The empty hbox ensures that a page is printed even for empty inputs, except
% when using psfrag which gets confused by it.
\fontsize{20.000000}{25.000000}%
\ifdefined\psfrag\else\hbox{}\fi%
{\sffamily $\mathdefault{01/01}
\end{document}

Operating system

Opensuse Tumbleweed

Matplotlib Version

3.5.0

Matplotlib Backend

module://matplotlib_inline.backend_inline

Python version

Python 3.9.7

Jupyter version

jupyter lab --version: 3.2.1

Installation

conda

@anntzer
Copy link
Contributor

anntzer commented Jan 29, 2022

I can reproduce the problem.

For reminder, the original "usetex support for dates" was requested in #2294; usetex was in fact already supported for date ticklabels but the specific problem was that date ticklabels were wrapped in \sffamily (like normal nonmath tex strings) which gave them a different font vs non-dates ticklabels (which get wrapped in $s and therefore use the default (seriffed) tex math font).

The solution implemented in #18558 was to also wrap the date ticklabels in $s and selectively escape parts of the TeX string which need to be processed as nonmath, but as #19836 and #21518 show this is a bit of a whack-a-mole game, and the issue here is another problem around the same lines (well, the details are a bit different, but still).

Another solution (perhaps better?) would be instead to revert all of #18558 and to just not wrap the tex string with \sffamily at all before handing it to TeX; this way the entire date ticklabel would be rendered using TeX's default (serif) font, matching the other ticklabels. In particular, this would mean that month names would also use a serif font, but I think this actually looks better (e.g. 01-Jan looks a bit weird when 01 is serif and Jan is sans-serif).

Right now removing the \sffamily is not possible (I directly modified texmanager.py to do that), but it should be possible to fix that with some work on texmanager.py...

@jklymak
Copy link
Member

jklymak commented Jan 29, 2022

I find text/usetext handling almost completely arbitrary in Matplotlib. I don't understand why non-math would be sans-serif, but math would have serifs - most latex documents are not setup this way, and I'd think folks who want latex fonts would want them to be consistent. Thats a slightly bigger comment than this case, but I'd argue wen we can be consistent, we should...

@anntzer
Copy link
Contributor

anntzer commented Jan 29, 2022

My guess is that this is "historical", but I agree the whole thing is a bit of a mess :/

@QuLogic
Copy link
Member

QuLogic commented Oct 6, 2022

#22361 was reverted in #24047, so this needs re-opening.

@QuLogic QuLogic reopened this Oct 6, 2022
@QuLogic QuLogic modified the milestones: v3.6.0, v3.7.0 Oct 6, 2022
@ksunden ksunden modified the milestones: v3.7.0, v3.7.1 Feb 14, 2023
@QuLogic QuLogic modified the milestones: v3.7.1, v3.7.2 Mar 4, 2023
@QuLogic QuLogic modified the milestones: v3.7.2, v3.7.3 Jul 5, 2023
@QuLogic QuLogic modified the milestones: v3.7.3, v3.8.0 Sep 9, 2023
@ksunden ksunden removed this from the v3.8.0 milestone Sep 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants