10

This is again one of the behaviors that are quite difficult to catch in a reconstructible (and simple) example, so one has to resort to animations.

Basically, the issue is this: the tilde (~) is supposed to be a non-breaking space character, right? How come, then, when I use the Fig.~\ref{fig:myfigure} in the MWE below, it sometimes ends up breaking the line exactly at that ~ character's location, as can be seen on the .gif below:

test-tilde-O2.gif

For instance, frame 41 there ends up like this (click for full res):

test-tilde-41.png

Isn't that what the tilde is supposed to prevent?

How can I find out why this is happening - and how can I get a non-breaking space in my Fig.~\ref{...} construct?

Below is the MWE, test-tilde.tex; it uses the package repeat-build.sty that I posted here (tested only on Linux currently) - and it needs to be built twice, with -shell-escape:

pdflatex -shell-escape test-tilde.tex # first time, refs wrong here
pdflatex -shell-escape test-tilde.tex # second time, refs ok (can enable the `convert` post action if desired)

... so that all PDFs, used in the animaton above, are generated.

EDIT: I modified the code, so it will build without the repeat-build.sty; and it will reconstruct the situation on the still screenshot above (where the variable \tester=87); then if you want to use repeat-build, simply (un)comment the corresponding lines.

The code is:

\documentclass[%
  12pt,
  journal,
  onecolumn,
  twoside,
  draftcls,
  letterpaper,
]{IEEEtran}

\usepackage[demo]{graphicx} %
\usepackage{xcolor} % \pagecolor
\pagecolor{yellow!15}
\usepackage[colorlinks=true,linkcolor=blue]{hyperref}

\usepackage[nopar]{lipsum}
\usepackage{xstring}
% https://tex.stackexchange.com/a/26808/2595
\makeatletter
\def\unpacklipsum#1#2#3{%
  \count@=#1\relax
  \advance\count@\m@ne
  \def#3{}%
  \loop\ifnum\count@<#2\relax
    \advance\count@\@ne
    \edef#3{#3\csname lipsum@\romannumeral\count@\endcsname}%
  \repeat}
% https://tex.stackexchange.com/a/168754/2595
\def\loremnchars[#1]#2{%
  \unpacklipsum{#1}{#1}{\myunpacked}%
  \StrMid{\myunpacked}{1}{#2}% same as \StrLeft{\myunpacked}{#2}
}
\def\eloremnchars#1#2#3{%
  \unpacklipsum{#1}{#1}{\myunpacked}%
  % \StrMid is not an expandable macro (can't go in \def) - but
  % can "return" by saving in #3
  \StrMid{\myunpacked}{1}{#2}[#3]
}
\def\getLoremParaNumChars#1#2{%
  \unpacklipsum{#1}{#1}{\myunpacked}%
  \StrLen{\myunpacked}[#2]
  \typeout{Lorem paragraph #1 has #2 characters}.
}
\makeatother

\usepackage[format=plain,font=small,skip=12pt]{caption} %
\usepackage{listings} %
\usepackage{units} %
\usepackage{floatrow}
\floatsetup[figure]{capposition=bottom}
\usepackage{etoolbox}
\usepackage{pgfplots}
\usepackage{pgfplotstable}
\usepackage{tikz}
\usetikzlibrary{shapes,positioning}
\usetikzlibrary{fit}
\usetikzlibrary{calc}
\usetikzlibrary{decorations.markings}
\usepackage{txfonts} % Times font in math; tlmgr install txfonts
\renewcommand{\ttdefault}{pcr}
\usepackage[UTF8]{ctex} % needs simsun.ttc in same directory
\usepackage{setspace}
\usepackage{siunitx}
\usepackage[american]{babel}
\usepackage{csquotes}
\makeatletter
\let\l@AMERICAN\l@american % https://tex.stackexchange.com/q/88861/
\makeatother
\usepackage[style=ieee,isbn=true,doi=false,url=true,backend=biber]{biblatex}


% here, set the \tester at a number,
% so we don't hit an error if we
% compile without repeat-build (-shell-escape)

% https://tex.stackexchange.com/a/185976/2595
%%%% uncomment the below part if you want to use {repeat-build}:
%   \ifx\tester\undefined{%
%     \global\protected\def\tester{100} %
%   }\fi
%   % do not rm the .aux here; need them for fig label;
%   % since the process needs to run twice for correct
%   % label - comment the convert post action.
%   %% manual convert command:
%   %% convert -verbose -density 150 test-tilde-*.pdf[0] -crop 1024x580+137+773 -resize 512x +repage -delay 15 -loop 0 test-tilde.gif
%   %% gifsicle -O2 test-tilde.gif -o test-tilde-O2.gif # helps reduce size
%   \def\pacode{%
%     pwd; %
%     ls \jobname-*.log \jobname-*.aux; %
%     rm -vrf \jobname-*.log ;% \jobname-*.aux; %
%   %   convert -verbose -density 75 \jobname-*.pdf[0] %
%   %     -crop 512x290+68+386 %
%   %     +repage %
%   %     -delay 15 -loop 0 % -delay 5
%   %     \jobname.gif %
%   %   ; %
%   %   eog \jobname.gif ; % run viewer
%   }
%   \usepackage[%
%     vartoken=\tester,%  % loop the variable token: \tester
%     varvals={15,16,...,29,41,42,...,52,58,59,...,65,77,78,...,89},% set \tester to change; (was from 0 to 100 {0,...,100})
%     postactioncode={\pacode},%
%   ]{repeat-build}
%   \unprotect\tester
%   \makeatletter
%   \def\getrjname{\rpbuild@jobname}
%   \makeatother
%%%% else this should be enough for a usual run:
\def\tester{83} % comment this if using repeat-build!

\begin{document}

  \title{Test title}
  \author{test}

  \maketitle

  \begin{abstract}
  The abstract text goes here.
  \end{abstract}

  \section{Test section}

  Test text, before figure:

  \setcounter{figure}{22} % if 10, then {figure} becomes 11
  \begin{figure}[h!t]
    \singlespacing
    \includegraphics[width=\textwidth,height=100pt]{demo.whatever}
    %\caption[shortdesc]{The figure is being shown here. \protect\loremnchars[3]{255}}
    \captionof{figure}[shortdesc]{The figure is being shown here. \protect\loremnchars[3]{255}}
    \label{fig:myfigure}
  \end{figure}

  Current: doc: \jobname; \verb!\tester!: \tester ... \loremnchars[1]{150}

  \eloremnchars{2}{\tester}{\tretA} %
  \pgfmathtruncatemacro{\tB}{\tester/2} %
  \eloremnchars{4}{\tB}{\tretB} %
  \eloremnchars{5}{\tester}{\tretC} %
  \tretA\space on Fig.~\ref{fig:myfigure}.
  \tretB\space on Fig.~\ref{fig:myfigure},
  \tretC\space on Fig.~\ref{fig:myfigure}.

  \loremnchars[3]{712}.. And ... \lipsum[7]

  %\getLoremParaNumChars{3}{\tret} %\typeout{\tret}
  %\eloremnchars{3}{712}{\tret} \typeout{\tret}

\end{document}
  • 4
    This is hardly a minimal test case. – Lev Bishop Jun 22 '14 at 5:27
  • Thanks for the comment, @LevBishop - the idea was to show that sometimes the ~ behaves as expected, and sometimes it doesn't; this is the collection of packages I have, and if one of them is the culprit, I have no idea of how to go about tracking it down (ergo, the "debugging" tag). Hope that's ok - cheers! – sdaau Jun 22 '14 at 5:29
  • 4
    The cases where ~ worked as expected aren't really needed, the only example needed was a single break at ~ a minimal example should include only the packages required to show the problem, not all the packages in your real document. – David Carlisle Jun 22 '14 at 8:17
  • Thanks, @DavidCarlisle - looking in retrospect, you're absolutely correct; but I was just so irritated that I encountered these "sometimes breaking" spaces, I just wanted to show in detail, what it was that was "disturbing" to me :) Cheers! – sdaau Jun 22 '14 at 13:07
17

Here's the MWE that was missing from the question:

\documentclass[12pt,onecolumn,draftcls]{IEEEtran}
\usepackage{ctex}
\begin{document}
%\show~
  Nam dui ligula, fringilla a, euismod sodales, sollicitudin vel, wisi.
  Morbi auctor \space on Fig.~23. Quisque ullamcorper placerat ipsum. 
  Cras \space on Fig.~23, Fusce mauris. Vestibulum luctus nibh at lectus. Sed 
  bibendum, nulla a faucibus semp \space on Fig.~23.
\end{document}

Uncommenting the \show~ tells us

> ~=macro:
->\hspace {0.25em plus 0.125em minus 0.08em}\ignorespaces . 
l.4   \show~

ie, breakable space, and removing the \usepackage{ctex} line sets it back to the usual

> ~=macro:
->\nobreakspace {}.
l.4   \show~

If you must use ctex then it seems that you can replace ~ by \nbs or you can use \standardtilde to restore the usual behaviour of ~.

  • 1
    +1 for the simplicity of the new MWE! Incidentally, the MWE -- or, more precisely, the package ctex that's loaded by the MWE -- seems to require the font simsun; unfortunately, this font doesn't seem to be present on MacOSX machines. :-( – Mico Jun 22 '14 at 6:59
  • 1
    @Mico The SimSun font is freely downloadable – egreg Jun 22 '14 at 9:21
  • 3
    The redefinition of ~, \nbs and \standardtilde are features of CJK.sty that is automatically loaded by ctex. – egreg Jun 22 '14 at 9:28
  • Fantastic - many thanks for the answer, @LevBishop; I tried some debugging in the meantime myself, and I concur: doing the equivalent of (the original) \def~{\nobreakspace{}} after \begin{document} works. Cheers! – sdaau Jun 22 '14 at 13:11
4

Just wanted to include some notes about my debugging procedure here.

Obviously, since the tilde is the problem, I first wanted to see what does it actually do. At first, I didn't even think it was a macro (I thought it was "just" a character with a "special catcode", I guess), and then I thought I'd try texdef in a console shell:

$ texdef -t latex '~'

\~:
macro:->\OT1-cmd \~\OT1\~ 

Ok, so it turns out, it may be a macro... Except, this is not the macro I was looking for: texdef automatically prepends a backslash, so what we actually see is the definition for the macro \~ (backslash tilde), not the definition for ~ (tilde).

At this point, things get complicated because it's difficult to search online; the tilde is an ASCII char (and so it doesn't have a html entities representation, as confirmed by php -r 'echo htmlentities("a~a\n",ENT_COMPAT,"UTF-8");') - and so, I cannot really search for a query like \def ~ in neither online search, nor the local here at Tex.SE. Somehow though, I noticed this in online search results:

[R] Tildes in R docmentation. - Grokbase

... ). \textasciitilde is a standard part of latex (in file latex.ltx). ...

Ah, so at least a pointer; so one can now do this from the terminal shell:

$ kpsewhich latex.ltx
/path/to/texlive/2011/texmf-dist/tex/latex/base/latex.ltx
$ grep '~' $(kpsewhich latex.ltx) | grep def
\chardef\active=13 \catcode`\~=\active % tilde is active
\def~{\errmessage{%
\def~{\typeout{! %
\def~{\nobreakspace{}}
     \lowercase{\endgroup\def~{\leavevmode\kern\z@\char`#1}}}

In addition, I also stumbled upon https://tex.stackexchange.com/a/59260/2595 and https://tex.stackexchange.com/a/66951/2595 - which to me confirmed that the original definition of tilde as a macro is \def~{\nobreakspace{}}.

Right, so what now? Well, first I'd thought I'd redefine tilde, so it prints out a message to stdout; so I thought, if it gets replaced by something, then the printing would stop, and point to the location where the redefinition occured. So I used this:

% should stop when something changes its def...
\newcounter{tildcount}
\typeout{tilde MEANING AT START: \meaning~ }
% tilde MEANING AT START: macro:->\nobreakspace {}
\let\origtilde~
\def~{%
  \stepcounter{tildcount}%
  % \meaning~ remains the same as before, as long as 
  % this \def is in place; so don't print it. 
  \typeout{tilde called \thetildcount\space times}%
  \origtilde%
}

So far so good - except this macro may crash on tildes inside a caption and such. And even worse, the redefinition doesn't occur in the middle of the document, so this ultimately doesn't help much.

So, the only thing that remained, was to print out \meaning~ throughout the entire document (preamble included), and see where it changes. So I did the equivalent of this (as in the test-tilde.tex above):

% https://tex.stackexchange.com/questions/81789/get-current-source-line-number/81794#81794
\def\showLineMean{\typeout{line \the\inputlineno; MEANING: \meaning~}}
...
\usetikzlibrary{calc} \showLineMean                    % l.61
\usetikzlibrary{decorations.markings} \showLineMean    % l.62
\usepackage{txfonts} \showLineMean % Times font ...    % l.63
\renewcommand{\ttdefault}{pcr} \showLineMean           % l.64
\usepackage[UTF8]{ctex} \showLineMean % simsun.ttc ... % l.65
\usepackage{setspace} \showLineMean                    % l.66
\usepackage{siunitx} \showLineMean                     % l.67
\usepackage[american]{babel} \showLineMean             % l.68
\usepackage{csquotes} \showLineMean                    % l.69
...
\usepackage[style=ieee,...]{biblatex} \showLineMean    % l.73
...
\showLineMean                                          % l.115
\begin{document}                                       % l.116
\showLineMean                                          % l.117

\title{Test title} ...

Then could to this:

$ pdflatex test-tilde.tex # ...
$ grep MEANING test-tilde.log 
line 61; MEANING: macro:->\nobreakspace {}
line 62; MEANING: macro:->\nobreakspace {}
line 63; MEANING: macro:->\nobreakspace {}
line 64; MEANING: macro:->\nobreakspace {}
line 65; MEANING: macro:->\nobreakspace {}
line 66; MEANING: macro:->\nobreakspace {}
line 67; MEANING: macro:->\nobreakspace {}
line 68; MEANING: macro:->\active@prefix ~\active@char~ 
line 69; MEANING: macro:->\active@prefix ~\active@char~ 
line 73; MEANING: macro:->\active@prefix ~\active@char~ 
line 115; MEANING: macro:->\active@prefix ~\active@char~ 
line 117; MEANING: macro:->\hspace {0.25em plus 0.125em minus 0.08em}\ignorespa

Hah! So the tilde ~ first changes when babel is loaded - and then, a second time, right after \begin{document}!

Of course, I couldn't see any logic behind this -- and as a last resort, I tried to look up the last of those meanings (the one in force during the document compilation) on the Internet; luckily, among the first results was:

This is the file commands.txt of the CJK macro package ver. 4.8.3 ...

\CJKtilde This command changes the definition of the active `~' character from an unbreakable space to \def~{\hspace{0.25em plus 0.125em minus 0.08em}}

Ah well, that finally confirmed what the problem is (and the solution is as on the accepted answer).

Somewhat sadly, however - after all of this, I cannot say that this is a debugging procedure I could have done only on a local machine, without lookups online... wish my procedure was more robust than this :)

Well, hope this helps someone,
Cheers!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.