2

I have a tikz-cd diagram where I would like each arrow to have a "glow", where the glow is the same colour as the arrow. How might I do this?

MWE

\documentclass{article}
\usepackage[dvipsnames]{xcolor}
\usepackage{tikz-cd}
\usetikzlibrary{shapes.geometric,arrows.meta}

\newcommand{\mysym}{\vphantom{\to}^{*}}

\begin{document}

\tikzset{
startip/.tip={Glyph[glyph math command=mysym]},
Rightarrow*/.style={PineGreen,double equal sign distance,>={Implies},->.startip},
to*/.style={PineGreen,->.startip}}
\begin{tikzcd}[
    column sep=small,
    cells={nodes={draw=black, ellipse, anchor=center, minimum height=2em}}
]
    a \arrow[r,Rightarrow*] 
    \arrow[Rightarrow*, bend left]{rrrrr} & a \arrow[Rightarrow*,r] & a
    \arrow[to*,r, Red] &
    |[draw=none,rectangle,inner sep=1pt]|a\vphantom{1} \arrow[Rightarrow*,r] & a \arrow[Rightarrow*,r] & a
\end{tikzcd}
\end{document}
5
  • 1
    This question is IMHO less innocent than one may think. In principle, glowing effects can be achieved along the lines of tex.stackexchange.com/a/80207/194703. However, in your case the contour of the path that is supposed to glow is rather complex, a mere playing with the line widths is not enough. I do not think that there will be a super simple solution that works for all possible arrow paths.
    – user194703
    May 13, 2020 at 18:04
  • @Schrödinger'scat Ultimately, what I am trying to achieve is make some arrow paths stand out against other arrow paths. Is there a better way to do this? May 13, 2020 at 22:35
  • 1
    One can definitely use something like this halo, but as you see from the example you need to also shorten the path. For curved paths this becomes tricky. There exist proposals to fix this, but you see how complex this starts to become. These are basically the problems that prevent me from using Paul Gaborit's nice post.
    – user194703
    May 13, 2020 at 22:46
  • Would it be possible if the curved line was removed? If that's the blocker, I can make a solution for non-curved lines work :) May 13, 2020 at 22:48
  • 2
    I can try to write something in a few hours. However, you may not have too large expectations. Of course, this does not mean that there cannot be an elegant, simple and general solution, maybe the approach outlined above is not the best one.
    – user194703
    May 13, 2020 at 22:50

2 Answers 2

2

I am not a big fan of the post-action approach. My approach to let a curve glow is based on the following two observations:

  • If we want a straight line glow, it can be done by \pgfdeclareverticalshading.
  • All curves are piece-wise linear.

To implement the idea, I first need to divide a tube into several rectangles

Of course they are not rectangles; but close enough.

Inside each rectangle, I need to place a shading.

I need to apply a proper transformation and a proper clip.

Luckily, the decorations.pathmorphing library does most of dirty jobs.

And here is a photo of LaTeX working hard to replace rectangles with shading.

Here is the final result

A closer look

For arrow heads, I believe it is a matter of redesigning the arrow head. If I were you, I'll simply use \pgfdeclareradialshading.

Playing code

\documentclass{article}
\usepackage{tikz-cd}
\usetikzlibrary{decorations.pathmorphing}

\begin{document}

define shading

\pgfdeclareverticalshading{simple_sh}{100bp}{
    color(0bp)=(transparent!100);
    color(25bp)=(transparent!100);
    color(40bp)=(transparent!100); % this point controls the width of the bean
    color(45bp)=(transparent! 75);
    color(50bp)=(transparent! 33); % this color control the shiny-ness
    color(55bp)=(transparent! 75);
    color(60bp)=(transparent!100); % this point controls the width of the bean%
    color(75bp)=(transparent!100);
    color(100bp)=(transparent!100)
}

\tikz{
    \draw(-50bp,-50bp)rectangle(50bp,50bp);
    \pgfuseshading{simple_sh}
}

$$$$

test fading

\pgfdeclarefading{simple_fa}{\pgfuseshading{simple_sh}}

pgfsetfading

\tikz{
    \fill[black!20](-1,-1)rectangle(2,2);
    \fill[black!30](0,0)arc(180:0:1);
    \pgfsetfading{simple_fa}{}
    \fill[red](-1,-1)rectangle (2,2);
}

pgfsetfadingforcurrentpath

\tikz{
    \pgfpathrectangle{\pgfpoint{0cm}{0cm}}{\pgfpoint{2cm}{1cm}}
    \pgfsetfadingforcurrentpath{simple_fa}{}
    \pgfsetfillcolor{red}
    \pgfusepath{fill}
}

$$$$

define the decoration

\makeatletter

define a gadget to remember points
\newlength\simple@xa        \newlength\simple@ya
\newlength\simple@xb        \newlength\simple@yb
\newlength\simple@xc        \newlength\simple@yc
\def\recordSimplePoint#1#2{
    \pgfpointtransformed{#2}
    \global\@nameuse{simple@x#1}=\pgf@x
    \global\@nameuse{simple@y#1}=\pgf@y
}
\def\useSimplePoint#1{
    \pgftransformreset
    \pgf@x=\@nameuse{simple@x#1}
    \pgf@y=\@nameuse{simple@y#1}
}

define a decoration that gives access to the local coordinate

\pgfdeclaredecoration{rail}{initial}{
    % 5bp here controls the resolution of the decoration
    \state{initial}[width=5bp,next state=segment]{
        % remember points
        \recordSimplePoint{a}{\pgfqpoint{0bp}{-10bp}}
        \recordSimplePoint{b}{\pgfqpoint{0bp}{0bp}}
        \recordSimplePoint{c}{\pgfqpoint{0bp}{10bp}}
    }
    % 5bp here controls the resolution of the decoration
    \state{segment}[width=5bp]{
        % draw the local rectangle
        \pgfpathmoveto{\useSimplePoint{a}}
        \pgfpathlineto{\useSimplePoint{c}}
        \pgfpathlineto{\pgfqpoint{0bp}{10bp}}
        \pgfpathlineto{\pgfqpoint{0bp}{-10bp}}
        \pgfpathclose
        \pgfusepath{stroke}
        % remember new points
        \recordSimplePoint{a}{\pgfqpoint{0bp}{-10bp}}
        \recordSimplePoint{b}{\pgfqpoint{0bp}{0bp}}
        \recordSimplePoint{c}{\pgfqpoint{0bp}{10bp}}
    }
    \state{final}{
    }
}

test the decoration

\tikz{
    \draw[decorate,decoration=rail]plot[samples=101,domain=0:3.5]
        (  {cos(300*\x) - 4*cos(200*\x)},
           {sin(300*\x) + 4*sin(200*\x)}   );
}

$$$$

define the actual decoration
\pgfdeclaredecoration{glow}{initial}{
    % 5bp here controls the resolution of the decoration
    \state{initial}[width=5bp,next state=segment]{
        % remember points
        \recordSimplePoint{a}{\pgfqpoint{0bp}{-10bp}}
        \recordSimplePoint{b}{\pgfqpoint{0bp}{0bp}}
        \recordSimplePoint{c}{\pgfqpoint{0bp}{10bp}}
    }
    % 5bp here controls the resolution of the decoration
    \state{segment}[width=5bp]{
        % draw the local rectangle
        \pgfscope
            \pgfpathmoveto{\useSimplePoint{a}}
            \pgfpathlineto{\useSimplePoint{c}}
            \pgfpathlineto{\pgfqpoint{0bp}{10bp}}
            \pgfpathlineto{\pgfqpoint{0bp}{-10bp}}
            \pgfpathclose
            % a vector pointing current (0,0) to previous (0,0) is
            %\pgfpointdiff
            %   {\pgfpointtransformed\pgfpointorigin}
            %   {\useSimplePoint{b}}
            % the angle of this vector is
            \pgfmathanglebetweenpoints
                {\pgfpointtransformed\pgfpointorigin}
                {\useSimplePoint{b}}
            \let\angleToPrevOrig=\pgfmathresult
            % use the fading, responsibly
            \pgfsetfading{simple_fa}{
                % Transform the shading such that
                % the axes of shadings "line-up"
                % The trick is to align the axis with the diff vector
                \pgftransformshift{\useSimplePoint{b}}
                \pgftransformrotate{\angleToPrevOrig}
            }
            \pgfsetfillcolor{red}
            \pgfusepath{fill}
        \endpgfscope
        % remember new points
        \recordSimplePoint{a}{\pgfqpoint{0bp}{-10bp}}
        \recordSimplePoint{b}{\pgfqpoint{0bp}{0bp}}
        \recordSimplePoint{c}{\pgfqpoint{0bp}{10bp}}
    }
    \state{final}{
    }
}
\makeatother

$$$$

working in progress

\pgfmathsetseed{543952}
\tikz{
    \foreach\x in{-5,...,4}{
        \foreach\y in{-5,...,4}{
            \draw[line width=rnd](\x,\y)+(rnd,rnd)
                ellipse[radius=rnd,y radius=rnd,rotate=rnd*360];
        }
    }
    \draw[decorate,decoration=glow]plot[samples=30,domain=0:1]
        (  {cos(300*\x) - 4*cos(200*\x)},
           {sin(300*\x) + 4*sin(200*\x)}   );

    \draw[decorate,decoration=rail]plot[samples=101,domain=1:3.5]
        (  {cos(300*\x) - 4*cos(200*\x)},
           {sin(300*\x) + 4*sin(200*\x)}   );
}
$$$$

final result

\pgfmathsetseed{543952}
\tikz{
    \foreach\x in{-5,...,4}{
        \foreach\y in{-5,...,4}{
            \draw[line width=rnd](\x,\y)+(rnd,rnd)
                ellipse[radius=rnd,y radius=rnd,rotate=rnd*360];
        }
    }
    \draw[decorate,decoration=glow]plot[samples=101,domain=0:3.5]
        (  {cos(300*\x) - 4*cos(200*\x)},
           {sin(300*\x) + 4*sin(200*\x)}   );
}

\end{document}
0

This is not a serious answer. The upshot is that one can get a glowing effect, but it is a lot of work and needs quite some adjustments. This basically implements Paul Gaborit's nice idea.

\documentclass{article}
\usepackage[dvipsnames]{xcolor}
\usepackage{tikz-cd}
\usetikzlibrary{shapes.geometric,arrows.meta}

\newcommand{\mysym}{\vphantom{\to}^{*}}
\tikzset{% very much based on https://tex.stackexchange.com/a/80207/194703
  glowing arrow layer/.style={
    line width=\pgfkeysvalueof{/tikz/glowing arrow pars/f}*\pgflinewidth,
    >/.expanded=\pgfkeysvalueof{/tikz/glowing arrow pars/head},
    draw=\pgfkeysvalueof{/tikz/glowing arrow pars/color},
  },
  glowing arrow recurs/.code={%
    \pgfmathtruncatemacro{\level}{#1-1}%
    \ifnum\level=0%
    \tikzset{postaction={glowing arrow layer}}%
    \else
    %\typeout{\level,\the\pgflinewidth}%
    \tikzset{postaction={glowing arrow layer,
    glowing arrow recurs={\level}}}%
    \fi
  },
  glowing arrow/.style={glowing arrow/.cd,#1,/tikz/.cd,
  draw,color/.expanded=\pgfkeysvalueof{/tikz/glowing arrow pars/color},
  preaction={line width/.expanded={%
  \pgfkeysvalueof{/tikz/glowing arrow pars/line width}*%
    pow(\pgfkeysvalueof{/tikz/glowing arrow pars/f},-\pgfkeysvalueof{/tikz/glowing arrow pars/n}/2)*\pgflinewidth},% 1/0.95^5=1.3
  draw opacity=\pgfkeysvalueof{/tikz/glowing arrow pars/opacity},
  glowing arrow recurs={\pgfkeysvalueof{/tikz/glowing arrow pars/n}}}},
  glowing arrow pars/.cd,n/.initial=10,color/.initial=PineGreen,
  f/.initial=0.95,opacity/.initial=0.1,line width/.initial=1.67pt,
  head/.initial={cm to}
}
\begin{document}

\tikzset{
startip/.tip={Glyph[glyph math command=mysym]},
Rightarrow*/.style={PineGreen,double equal sign distance,>={Implies},->.startip},
to*/.style={glowing arrow,
>={Computer Modern Rightarrow[length=2.8pt,width=6.2pt]},->.startip,
glowing arrow pars/color=PineGreen,
glowing arrow pars/head={Computer Modern Rightarrow[length=2.8pt+\the\pgflinewidth/2-0.2pt,
        width=6.2pt+\the\pgflinewidth/2-0.2pt]}}}
\begin{tikzcd}[
    column sep=small,
    cells={nodes={draw=black, ellipse, anchor=center, minimum height=2em}}
]
    a \arrow[r,Rightarrow*] 
    \arrow[Rightarrow*, bend left]{rrrrr} & a \arrow[Rightarrow*,r] & a
    \arrow[to*,r] &
    |[draw=none,rectangle,inner sep=1pt]|a\vphantom{1} \arrow[Rightarrow*,r] & a \arrow[Rightarrow*,r] & a
\end{tikzcd}
\end{document}

enter image description here

The Rightarrow will be even harder...

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.