11

Suppose that an arrow can be

  1. With one head (o), two heads (t), or "squiggly" (g),
  2. Single-lined (s) or double-lined (d),
  3. With (w) or without (o) a label (i.e., text above)

Some of those arrows are defined by "standard" packages, like \xrightarrow{abc}, which corresponds to osw, some of them needs more "exotic" packages, like \xLongrightarrow (tdw), defined by extarrows.

Some needs to be drawn with Tikz, like \xtwoheadrightarrow (tsw), cf. https://tex.stackexchange.com/a/60219/34551

I tried to have a macro allowing me to define all those combinations at once, and to display them with a uniform appearance. I tried to use xparse and l3regex, which seemed to be a good combination to handle it (shout-out to https://tex.stackexchange.com/a/188593/34551).

I think I managed to define a macro that define them all at once, but they look terrible, i.e., really not uniform, and the hack I used for tdw is simply awful.

Should I give up my idea of taking an arrow there and another there, and just draw them all in tiKz? How to make sure, in this case, that they do behave like mathematical operators?

Here's what I managed to get:

enter image description here

Using the following code:

\documentclass{article}
\usepackage{xparse,l3regex}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{extarrows} % For \xLongrightarrow
\usepackage{mathtools}
\usepackage{tikz}
\usetikzlibrary{calc,decorations.pathmorphing,shapes,arrows}

\newcommand\xRightsquigarrow[1]{% https://tex.stackexchange.com/a/83086
  \mathrel{%
    \begin{tikzpicture}[baseline= {( $ (current bounding box.south) + (0,-0.5ex) $ )}]
      \node[inner sep=.5ex] (a) {$\scriptstyle #1$};
      \path[draw,implies-,double distance between line centers=1.5pt,decorate,
      decoration={zigzag,amplitude=0.7pt,segment length=1.2mm,pre=lineto,
    pre   length=4pt}] 
      (a.south east) -- (a.south west);
    \end{tikzpicture}}%
}
\newcommand\Rightsquigarrow{%
  \mathrel{%
    \begin{tikzpicture}[baseline= {( $ (current bounding box.south) + (0,-0.5ex) $ )}]
      \node[inner sep=.5ex] (a) {\hspace*{1em}};
      \path[draw,implies- ,double distance between line centers=1.5pt,decorate,
      decoration={zigzag,amplitude=0.7pt,segment length=1.2mm,pre=lineto,
    pre   length=4pt}] 
      (a.south east) -- (a.south west);
    \end{tikzpicture}}%
}

\makeatletter % https://tex.stackexchange.com/a/114242/34551
\providecommand*{\twoheadrightarrowfill@}{%
  \arrowfill@\relbar\relbar\twoheadrightarrow
}
\providecommand*{\xtwoheadrightarrow}[2][]{%
  \ext@arrow 0579\twoheadrightarrowfill@{#1}{#2}%
}
\makeatother

\ExplSyntaxOn
\NewDocumentCommand{\ar}{ m o }
{
  \IfNoValueTF{#2}
  {% there is no trailing optional argument, set the boolean to false
    \bool_set_false:N \l_label_bool
  }
  {% there is a trailing optional argument, set the boolean to true
    \bool_set_true:N \l_label_bool
    % and store the argument for later usage
    \tl_set:Nn \l_label_tl { #2 }
  }
  \ar_short:n { #1 }
}


% First byte: o, t, g     (one head, two heads, squiggly)
% Second byte: s, d       (single or double)
% Third byte:             (label to write on it)

\bool_new:N \l_label_bool
\tl_new:N \l_label_tl

\cs_new_protected:Npn \ar_short:n #1
{% separate the two characters
  \ar_short_aux:NN #1
}

\cs_new_protected:Npn \ar_short_aux:NN #1 #2{
  \str_case:nn { #1 }
  {
    {o}% One head
    {
      \str_case:nn { #2 }
      {{s}{% Single
      \xtwoheadrightarrow[]{  \bool_if:NT \l_label_bool { \l_label_tl }}
    }{d}{% Double
      \xRightarrow{  \bool_if:NT \l_label_bool { \l_label_tl }}\!\!\!\!\Rightarrow}
      }
    }
    {t}% Two heads
    {\str_case:nn { #2 }
      {{s}{% Single
      \xrightarrow{  \bool_if:NT \l_label_bool { \l_label_tl }}
    }{d}{% Double
      \xLongrightarrow{  \bool_if:NT \l_label_bool { \l_label_tl }}
    }
      }
    }
    {g}% Squiggly
    {\str_case:nn { #2 }
      {{s}{% Single
      \bool_if:NTF \l_label_bool {\overset{\l_label_tl}{\rightsquigarrow}}{\rightsquigarrow}
    }
    {d}{% Double
      \bool_if:NTF \l_label_bool {\xRightsquigarrow{\l_label_tl}}{\Rightsquigarrow}}
      }
    }
  }
}



\ExplSyntaxOff

\begin{document}

  $a \ar{os} b$

  $a \ar{od} b$

  $a \ar{ts} b$

  $a \ar{td} b$

  $a \ar{gs} b$

  $a \ar{gd} b$

  $a \ar{os}[i_2 : \alpha, 34] b$

  $a \ar{od}[i_2 : \alpha, 34] b$

  $a \ar{ts}[i_2 : \alpha, 34] b$

  $a \ar{td}[i_2 : \alpha, 34] b$

  $a \ar{gs}[i_2 : \alpha, 34] b$

  $a \ar{gd}[i_2 : \alpha, 34] b$

\end{document}

The difference of spacing between them, and the fact that one of them (gsw) is not extensible, are what bug me the most.

  • Should you allow subscripts too? :) – Andrew Aug 12 '16 at 6:43
  • Well, if you want to make it harder, sure ;-). I could also asked for "starred" version, i.e., with a star as an exponent, to denote transitivity, but I think that, generally, a ^* is enough for that. – Clément Aug 12 '16 at 6:48
  • If you really want to make it harder, I guess an arrow can be barred, too, to denote that b is not accessible from a using that kind of transition. \centernot is not always good-looking… – Clément Aug 12 '16 at 7:02
  • Isn't it rather confusing to use o for two different things? – cfr Aug 24 '16 at 23:52
  • 1
    xypic has a powerful engine generating arrows. You might want to study its logic. – Symbol 1 Aug 30 '16 at 14:56
9
+150

Substantially REVISED to achieve what was missing on the earlier post. Namely, all desired arrow types are supported (albeit with wavy, rather than jagged, squiggle), uniform arrow lengths are achieved for a given overset, regardless of arrow type, all math styles are supported.

Some tweaks would be required for a font-size change (currently 10pt) in order to achieve uniformly sized building blocks and arrowheads (see bottom of answer for details).

I have not wrapped it in an overarching macro, but the individual arrow types are called \zigzagarrow (single squiggly line, single arrowhead), \ZigZagarrow (double squiggly line, single arrowhead), \linearrow (single line, single arrowhead), \Linearrow (double line, single arrowhead), \zzigzagarrow (single squiggly line, double arrowhead), \ZZigZagarrow (double squiggly line, double arrowhead), \llinearrow (single line, double arrowhead), and \LLinearrow (double line, double arrowhead),

\documentclass[10pt]{article}
\usepackage{stackengine,scalerel,graphicx,trimclip,amsmath,wasysym}
% UNIFORMLY SIZED BUILDING BLOCKS
\savestack\zigzagtextstyle{\vphantom{()}\scalebox{.86666}[1]{\kern-.5pt\AC\kern-.5pt}}
\savestack\onelinetextstyle{\vphantom{()}\scalebox{1}[1]{\kern-1pt{$-$}\kern-1pt}}
\savestack\twolinetextstyle{\vphantom{()}\scalebox{1}[1]{\kern-1pt{$=$}\kern-1pt}}
\savestack\ZigZagtextstyle{% DERIVATIVE OF \zigzagtextstyle
  $\vphantom{()}\smash{\raisebox{-.002em}{$\vcenter{\hbox{%
   \stackengine{-.805em}{\zigzagtextstyle}{\zigzagtextstyle}{O}{c}{F}{F}{S}}}$}}$}
\newlength\repwidth
\repwidth=\wd\zigzagtextstylecontent\relax
% UNIFORMLY SIZED ARROWHEADS
\newcommand\rightarrowhead{\clipbox{4pt -2pt 0pt -2pt}{$\rightarrow$}}
\newcommand\Rightarrowhead{\clipbox{4pt -2pt 0pt -2pt}{$\Rightarrow$}}
\newcommand\rrightarrowhead{\clipbox{5.5pt -2pt 0pt -2pt}{$\rightarrow\kern-8.5pt\rightarrow$}}
\newcommand\RRightarrowhead{\clipbox{5.5pt -2pt 0pt -2pt}{$\Rightarrow\kern-8.5pt\Rightarrow$}}
% HALF-CYCLE BLOCKS PLUS ARROWHEAD
\newcommand\fXarrowtextstyle[2]{$\vphantom{()}\smash{\vcenter{\hbox{\kern-.03\repwidth%
   \clipbox{-.03\repwidth{} 0pt .527\repwidth{} 0pt}{#1}}}}#2$}
%
\savestack\fzigarrowtextstyle{\fXarrowtextstyle{\zigzagtextstyle}{\rightarrowhead}}
\savestack\fZigarrowtextstyle{\fXarrowtextstyle{\ZigZagtextstyle}{\Rightarrowhead}}
\savestack\flinearrowtextstyle{\fXarrowtextstyle{\onelinetextstyle}{\rightarrowhead}}
\savestack\fLinearrowtextstyle{\fXarrowtextstyle{\twolinetextstyle}{\Rightarrowhead}}
\savestack\fzzigarrowtextstyle{\fXarrowtextstyle{\zigzagtextstyle}{\rrightarrowhead}}
\savestack\fZZigarrowtextstyle{\fXarrowtextstyle{\ZigZagtextstyle}{\RRightarrowhead}}
\savestack\fllinearrowtextstyle{\fXarrowtextstyle{\onelinetextstyle}{\rrightarrowhead}}
\savestack\fLLinearrowtextstyle{\fXarrowtextstyle{\twolinetextstyle}{\RRightarrowhead}}
% SUPPORT FOR ALL MATH STYLES
%  - CYCLE BLOCKS
\newcommand\zigzag{\scalerel*{\zigzagtextstyle}{()}}
\newcommand\ZigZag{\scalerel*{\ZigZagtextstyle}{()}}
\newcommand\oneline{\scalerel*{\onelinetextstyle}{()}}
\newcommand\twoline{\scalerel*{\twolinetextstyle}{()}}
%  - ARROW HEADS
\newcommand\fzigarrow{\scalerel*{\fzigarrowtextstyle}{()}}
\newcommand\fZigarrow{\scalerel*{\fZigarrowtextstyle}{()}}
\newcommand\flinearrow{\scalerel*{\flinearrowtextstyle}{()}}
\newcommand\fLinearrow{\scalerel*{\fLinearrowtextstyle}{()}}
\newcommand\fzzigarrow{\scalerel*{\fzzigarrowtextstyle}{()}}
\newcommand\fZZigarrow{\scalerel*{\fZZigarrowtextstyle}{()}}
\newcommand\fllinearrow{\scalerel*{\fllinearrowtextstyle}{()}}
\newcommand\fLLinearrow{\scalerel*{\fLLinearrowtextstyle}{()}}
% ARROW-EXTENDING USER MACROS
\newcommand\zigzagarrow[1][]{\Xarrow{\zigzag}{\fzigarrow}{#1}{-.65}}
\newcommand\ZigZagarrow[1][]{\Xarrow{\ZigZag}{\fZigarrow}{#1}{-.40}}
\newcommand\linearrow[1][]{\Xarrow{\oneline}{\flinearrow}{#1}{-.65}}
\newcommand\Linearrow[1][]{\Xarrow{\twoline}{\fLinearrow}{#1}{-.40}}
\newcommand\zzigzagarrow[1][]{\Xarrow{\zigzag}{\fzzigarrow}{#1}{-.65}}
\newcommand\ZZigZagarrow[1][]{\Xarrow{\ZigZag}{\fZZigarrow}{#1}{-.40}}
\newcommand\llinearrow[1][]{\Xarrow{\oneline}{\fllinearrow}{#1}{-.65}}
\newcommand\LLinearrow[1][]{\Xarrow{\twoline}{\fLLinearrow}{#1}{-.40}}
% \Xarrow EXTENDING-ARROW MACRO
% #1 - arrow building block
% #2 - arrowhead
% #3 - overtext
% #4 - overset distance multiplier wrt top of paren
\newcommand\Xarrow[4]{\ThisStyle{\mathrel{\Xarrowhelp{#1#2}{#3}{#1}{#4}}}}
\newcommand\Xarrowhelp[4]{%
  \setbox0=\hbox{$\SavedStyle#1$}%
  \setbox2=\hbox{$\SavedStyle_{\,\,#2\,\,}$}%
  \ifdim\wd0<\wd2\relax\Xarrowhelp{#3#1}{#2}{#3}{#4}%
  \else\stackengine{#4\LMex}{\copy0}{\copy2\,}{O}{c}{F}{T}{S}\fi%
}
\begin{document}
\setstackEOL{\\}
\Longunderstack{
3 cycles:
\\
$\zigzagtextstyle\zigzagtextstyle\zigzagtextstyle$
\setbox0=\hbox{\zigzagtextstyle}\the\wd0
\\
$\ZigZagtextstyle\ZigZagtextstyle\ZigZagtextstyle$
\setbox0=\hbox{\zigzagtextstyle}\the\wd0
\\
$\onelinetextstyle\onelinetextstyle\onelinetextstyle$
\setbox0=\hbox{\onelinetextstyle}\the\wd0
\\
$\twolinetextstyle\twolinetextstyle\twolinetextstyle$
\setbox0=\hbox{\twolinetextstyle}\the\wd0
}
\qquad\Longunderstack{
Arrowheads:
\\
\rightarrowhead\setbox0=\hbox{\rightarrowhead}\the\wd0
\\
\Rightarrowhead\setbox0=\hbox{\Rightarrowhead}\the\wd0
\\
\rrightarrowhead\setbox0=\hbox{\rrightarrowhead}\the\wd0
\\
\RRightarrowhead\setbox0=\hbox{\RRightarrowhead}\the\wd0
}
\qquad\Longunderstack{
Half-cycle + arrowheads
\\
\fzigarrowtextstyle \quad \fzzigarrowtextstyle
\\
\fZigarrowtextstyle \quad \fZZigarrowtextstyle
\\
\flinearrowtextstyle \quad \fllinearrowtextstyle
\\
\fLinearrowtextstyle \quad \fLLinearrowtextstyle
}

Examples:

\Shortunderstack{
$A \zigzagarrow B \zigzagarrow[T=298K] C$
\\
$A \ZigZagarrow B \ZigZagarrow[T=298K] C$
\\
$A \linearrow B \linearrow[T=298K] C$
\\
$A \Linearrow B \Linearrow[T=298K] C$
\\
$A \zzigzagarrow B \zzigzagarrow[T=298K] C$
\\
$A \ZZigZagarrow B \ZZigZagarrow[T=298K] C$
\\
$A \llinearrow B \llinearrow[T=298K] C$
\\
$A \LLinearrow B \LLinearrow[T=298K] C$
}
\quad
\Shortunderstack{
$\scriptstyle A \zigzagarrow B \zigzagarrow[T=298K] C$
\\
$\scriptstyle A \ZigZagarrow B \ZigZagarrow[T=298K] C$
\\
$\scriptstyle A \linearrow B \linearrow[T=298K] C$
\\
$\scriptstyle A \Linearrow B \Linearrow[T=298K] C$
\\
$\scriptstyle A \zzigzagarrow B \zzigzagarrow[T=298K] C$
\\
$\scriptstyle A \ZZigZagarrow B \ZZigZagarrow[T=298K] C$
\\
$\scriptstyle A \llinearrow B \llinearrow[T=298K] C$
\\
$\scriptstyle A \LLinearrow B \LLinearrow[T=298K] C$
}
\quad
\Shortunderstack{
$\scriptscriptstyle A \zigzagarrow B \zigzagarrow[T=298K] C$
\\
$\scriptscriptstyle A \ZigZagarrow B \ZigZagarrow[T=298K] C$
\\
$\scriptscriptstyle A \linearrow B \linearrow[T=298K] C$
\\
$\scriptscriptstyle A \Linearrow B \Linearrow[T=298K] C$
\\
$\scriptscriptstyle A \zzigzagarrow B \zzigzagarrow[T=298K] C$
\\
$\scriptscriptstyle A \ZZigZagarrow B \ZZigZagarrow[T=298K] C$
\\
$\scriptscriptstyle A \llinearrow B \llinearrow[T=298K] C$
\\
$\scriptscriptstyle A \LLinearrow B \LLinearrow[T=298K] C$
}
\end{document}

enter image description here

As mentioned earlier, the key is achieving uniformly sized building blocks (cycles and arrowheads, respectively). For 12pt font, here are tweaks required to achieve that:

\savestack\onelinetextstyle{\vphantom{()}\scalebox{.97196}[1]{\kern-1.1pt{$-$}\kern-1.1pt}}
\savestack\twolinetextstyle{\vphantom{()}\scalebox{.97121}[1]{\kern-1pt{$=$}\kern-1pt}}

\newcommand\rrightarrowhead{\clipbox{6.5pt -2pt 0pt -2pt}{$\rightarrow\kern-9.5pt\rightarrow$}}
\newcommand\RRightarrowhead{\clipbox{6.5pt -2pt 0pt -2pt}{$\Rightarrow\kern-9.5pt\Rightarrow$}}

enter image description here

| improve this answer | |
  • Thanks for your detailed and really useful answer. I find the space above the label to be insufficient, as witness by the following example: \begin{tabular}{c} t\\ \hline $ B \zigzagarrow[T=298K] C$ \end{tabular}. I don't manage to patch it myself, do you have any suggestion? – Clément Sep 21 '16 at 20:30
  • @Clément One easy workaround is \addstackgap[3pt]{$ B \zigzagarrow[T=298K] C$} or [4pt]. I'll try to think of an automated fix. – Steven B. Segletes Sep 22 '16 at 0:16
  • @Clément If you add $\mathstrut$ just before \copy2 in the last line of the \Xarrowhelp definition, this will add extra vertical space needed. However, the -.65 and -.40 parameters in the \zigzagarrow et al definitions may have to be larger in magnitude, for example -.85 and -.60. – Steven B. Segletes Sep 22 '16 at 0:31

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.