使用 tikz 绘制高斯形式的黑白渐变矩形

使用 tikz 绘制高斯形式的黑白渐变矩形

我想制作一个矩形,水平方向比垂直方向长,左右两端为黑色,中间为白色。我不想要从黑色到白色(再变回黑色)的线性渐变,而是钟形曲线形式的变化。

我见过,这看起来很笼统,但我无法将任意函数改为简单的高斯函数。我希望有一种更简单的方法。

以下是我能做到的最好的事情:

% !TEX program = xelatex   
\documentclass[tikz]{standalone}                                     
\begin{document}   
                                                  
\begin{pgfpicture}                                                   
\pgfdeclarehorizontalshading{myshadingD}  {20pt}{color(0pt)=(black); color(40pt)=(white)}   
\pgfdeclarehorizontalshading{myshadingA}  {20pt}{color(0pt)=(white); color(40pt)=(black)} 
\pgftext[at=\pgfpoint{0cm}{0cm}] {\pgfuseshading{myshadingD}}    
\pgftext[at=\pgfpoint{2cm}{0cm}] {\pgfuseshading{myshadingA}}      
\end{pgfpicture}       
                                            
\end{document}    

这会创建如下内容:

在此处输入图片描述

答案1

由于定义\pgfdeclarefunctionshading需要大量的数学和 PostScript,我只需预先计算几个值。

我正在使用 LibreOffice Calc,因为它是我手头上最简单的工具,我可以使用它的功能来创建必要的

color(<length>)=(<outer>!<share>!<inner>);

在单独的列中声明,我只需要将其复制到我的 TeX 源中。

对于\pgftext{\pgfuseshading{<name>}}命令 I,将计算0pt和之间的 41 个值,40pt这些值将映射到 −π 和 +π。

自从PGF 变换路径上的阴影相反,我们将使用25bp75bp来表示相同的±π范围(总共 51 个值)。

阴影可用的在 PGF/TikZ 中我调用Gaussian(与 相比gaussian\pgftext

gauss outer colorgauss inner color可用于改变颜色。

我的文档中的最后一个例子将Gaussian阴影与默认(严格线性)axis阴影进行了比较。

也许这可以用更少的点来完成,但仍然足够,但肯定比用 PostScript 编码的工作量要少。

代码

% !TEX program = xelatex
\PassOptionsToPackage{rgb}{xcolor}
\documentclass{article}
\usepackage{tikz}
\pgfdeclarehorizontalshading[black]{gaussian}{20pt}{
color(0pt)=(black!99);color(1pt)=(black!99);color(2pt)=(black!98);color(3pt)=(black!97);color(4pt)=(black!96);
color(5pt)=(black!94);color(6pt)=(black!91);color(7pt)=(black!88);color(8pt)=(black!83);color(9pt)=(black!78);
color(10pt)=(black!71);color(11pt)=(black!63);color(12pt)=(black!55);color(13pt)=(black!45);color(14pt)=(black!36);
color(15pt)=(black!27);color(16pt)=(black!18);color(17pt)=(black!11);color(18pt)=(black!5);color(19pt)=(black!1);
color(20pt)=(black!0);color(21pt)=(black!1);color(22pt)=(black!5);color(23pt)=(black!11);color(24pt)=(black!18);
color(25pt)=(black!27);color(26pt)=(black!36);color(27pt)=(black!45);color(28pt)=(black!55);color(29pt)=(black!63);
color(30pt)=(black!71);color(31pt)=(black!78);color(32pt)=(black!83);color(33pt)=(black!88);color(34pt)=(black!91);
color(35pt)=(black!94);color(36pt)=(black!96);color(37pt)=(black!97);color(38pt)=(black!98);color(39pt)=(black!99);
color(40pt)=(black!99)}
\pgfdeclarehorizontalshading[gauss@border,gauss@center]{Gaussian}{100bp}{
color(0bp)=(gauss@border!100!gauss@center);color(25bp)=(gauss@border!99!gauss@center);color(26bp)=(gauss@border!99!gauss@center);
color(27bp)=(gauss@border!98!gauss@center);color(28bp)=(gauss@border!98!gauss@center);color(29bp)=(gauss@border!97!gauss@center);
color(30bp)=(gauss@border!96!gauss@center);color(31bp)=(gauss@border!94!gauss@center);color(32bp)=(gauss@border!92!gauss@center);
color(33bp)=(gauss@border!90!gauss@center);color(34bp)=(gauss@border!87!gauss@center);color(35bp)=(gauss@border!83!gauss@center);
color(36bp)=(gauss@border!79!gauss@center);color(37bp)=(gauss@border!74!gauss@center);color(38bp)=(gauss@border!68!gauss@center);
color(39bp)=(gauss@border!62!gauss@center);color(40bp)=(gauss@border!55!gauss@center);color(41bp)=(gauss@border!47!gauss@center);
color(42bp)=(gauss@border!40!gauss@center);color(43bp)=(gauss@border!32!gauss@center);color(44bp)=(gauss@border!25!gauss@center);
color(45bp)=(gauss@border!18!gauss@center);color(46bp)=(gauss@border!12!gauss@center);color(47bp)=(gauss@border!7!gauss@center);
color(48bp)=(gauss@border!3!gauss@center);color(49bp)=(gauss@border!1!gauss@center);color(50bp)=(gauss@border!0!gauss@center);
color(51bp)=(gauss@border!1!gauss@center);color(52bp)=(gauss@border!3!gauss@center);color(53bp)=(gauss@border!7!gauss@center);
color(54bp)=(gauss@border!12!gauss@center);color(55bp)=(gauss@border!18!gauss@center);color(56bp)=(gauss@border!25!gauss@center);
color(57bp)=(gauss@border!32!gauss@center);color(58bp)=(gauss@border!40!gauss@center);color(59bp)=(gauss@border!47!gauss@center);
color(60bp)=(gauss@border!55!gauss@center);color(61bp)=(gauss@border!62!gauss@center);color(62bp)=(gauss@border!68!gauss@center);
color(63bp)=(gauss@border!74!gauss@center);color(64bp)=(gauss@border!79!gauss@center);color(65bp)=(gauss@border!83!gauss@center);
color(66bp)=(gauss@border!87!gauss@center);color(67bp)=(gauss@border!90!gauss@center);color(68bp)=(gauss@border!92!gauss@center);
color(69bp)=(gauss@border!94!gauss@center);color(70bp)=(gauss@border!96!gauss@center);color(71bp)=(gauss@border!97!gauss@center);
color(72bp)=(gauss@border!98!gauss@center);color(73bp)=(gauss@border!98!gauss@center);color(74bp)=(gauss@border!99!gauss@center);
color(75bp)=(gauss@border!99!gauss@center);color(100bp)=(gauss@border!100!gauss@center)}
\makeatletter
\tikzset{
  gauss outer color/.code=\colorlet{gauss@border}{#1}\def\tikz@shading{Gaussian}\tikz@addmode{\tikz@mode@shadetrue},
  gauss inner color/.code=\colorlet{gauss@center}{#1}\def\tikz@shading{Gaussian}\tikz@addmode{\tikz@mode@shadetrue}}
\makeatother
\colorlet{gauss@border}{black}
\colorlet{gauss@center}{white}

\begin{document}

Let $a$ and $b$ be the first and the last length of the shading which should be mapped to the range $z = (-\pi, \pi)$ then is
\begin{equation}
z = \pi \left(2 \frac{i-a}{b-a}-1\right).
\end{equation}
The share of the color in range $c = (0, 100)$ is then
\begin{equation}
  c(i) = 100 \left(1- \frac{\phi(z)}{\phi(0)}\right).
\end{equation}

\texttt{gaussian}: $a = 0\,\mathrm{pt}$, $b = 40\,\mathrm{pt}$ \quad
\texttt{Gaussian}: $a = 25\,\mathrm{bp}$, $b = 75\,\mathrm{bp}$

\begin{tikzpicture}[x=20pt,y=20pt]
\pgftext[at=\pgfpoint{0pt}{0pt}]{\pgfuseshading{gaussian}}
\draw[overlay,very thick,red] plot[domain=-1:1, samples=100] 
  (\x,{exp(-(\x*\x*pi*pi)/2)/sqrt(2*pi)});
\end{tikzpicture}

\tikz\shade[shading=Gaussian] (0,0) rectangle (3,1);

\begin{tikzpicture}
\shade[gauss outer color=green, gauss inner color=magenta]
  (0, 0) coordinate (bl) rectangle ++(2.5, 1) coordinate (tr);

\fill[magenta] ([shift=(up:1)] bl) rectangle ++(1.25, -.25)
  ++ (down:.5) rectangle ++(1.25, -.25);
\shade[left color=green, right color=magenta]
  (bl) rectangle ++ (1.25, .25) coordinate (m);
\shade[left color=magenta, right color=green]
  (tr) rectangle ++ (-1.25, -.25);
\end{tikzpicture}
\end{document}

输出

在此处输入图片描述 在此处输入图片描述 在此处输入图片描述

答案2

伪造的阴影

  1. 使用填充的rectangles:fake shading
  2. 通过使用阴影rectangles: real fake shading

出了点问题path picture这就是为什么其中real fake shading有一个空白,否则第一个阴影矩形就不会被阴影。\shade;

除了该\shade;命令之外,我还使用 PGF 宏来希望能加快编译速度。

我们可以将函数设置为对某些东西进行着色,其中对fakeshading/function=<func>介于和之间的值进行求值<func>,并将 设置为介于和之间的值。\x010100

请注意,使用 一步fake shading仍然.01可以看到 的边缘。real fake shading.05

代码

% !TEX program = xelatex
\PassOptionsToPackage{rgb}{xcolor}
\documentclass[tikz]{standalone}
\pgfqkeys{/tikz/fakeshading}{
  colorA/.initial=black,
  colorB/.initial=white,
  function/.initial={%
    (100-100*phi(6.28318530717959*\x-3.14159265358979)/0.398942280401433)},
  step/.initial=.01}
\makeatletter
\def\fake@shading@function{max(0,min(100,\pgfkeysvalueof{/tikz/fakeshading/function}))}
\tikzset{
  declare function={phi(\z)=exp(-\z*\z/2)/sqrt(2*pi);},
  fake shading/.default=,real fake shading/.default=,
  fake shading/.style={ path picture={%
      \tikzset{every fake shading/.try,/tikz/fakeshading/.cd,#1}\fake@shading@setup
      \pgfmathmultiply@{.5}{\fake@shading@step}% half step length
      \let\fake@shading@halfstep\pgfmathresult
      \foreach \x[expand list,evaluate={\y=\fake@shading@function;}]
        in {0,\pgfkeysvalueof{/tikz/fakeshading/step},...,1.001} {
%       \fill[color=fake@shading@A!\y!fake@shading@B] (\x-\fake@shading@halfstep,0)
%                           rectangle ++(\pgfkeysvalueof{/tikz/fakeshading/step},1);
        \pgfpathrectangle{\pgfpointxy{\x-\fake@shading@halfstep}{0}}%
                         {\pgfpointxy{\pgfkeysvalueof{/tikz/fakeshading/step}}{1}}
        \pgfsetfillcolor{fake@shading@A!\y!fake@shading@B}\pgfusepath{fill}}}},
  real fake shading/.style={path picture={%
      \tikzset{every real fake shading/.try,/tikz/fakeshading/.cd,#1}\fake@shading@setup
      \pgfmathmultiply@{\fake@shading@step}{2}\let\fake@shading@doublestep\pgfmathresult
      \def\x{0}\pgfmathsetmacro\fake@shading@lasty{\fake@shading@function}%
      \shade;% the first shade doesn't want to
      \foreach \x[expand list,evaluate={\y=\fake@shading@function;},
        remember=\y as \lasty (initially \fake@shading@lasty)%
      ] in {\fake@shading@step,\fake@shading@doublestep,...,1.001} {
        \pgfutil@colorlet{tikz@axis@top}{fake@shading@A!\lasty!fake@shading@B}%
        \pgfutil@colorlet{tikz@axis@bottom}{fake@shading@A!\y!fake@shading@B}%
        \pgfutil@colorlet{tikz@axis@middle}{tikz@axis@top!50!tikz@axis@bottom}%
        \pgfpathrectangle{\pgfpointxy{\x}{0}}{\pgfpointxy{-\fake@shading@step}{1}}
        \pgfshadepath{axis}{90}\pgfusepath{}}}}}
\def\fake@shading@setup{%
  \pgftransformreset
  \colorlet{fake@shading@A}{\pgfkeysvalueof{/tikz/fakeshading/colorA}}%
  \colorlet{fake@shading@B}{\pgfkeysvalueof{/tikz/fakeshading/colorB}}%
  \pgfextract@process\tikz@temp{% setting up coordinate system
    \pgfpointdiff{\pgfpointanchor{path picture bounding box}{south west}}
                 {\pgfpointanchor{path picture bounding box}{north east}}}%
  \pgfsetxvec{\tikz@temp\pgf@y0pt }\pgfsetyvec{\tikz@temp\pgf@x0pt }%
  \pgftransformshift{\pgfpointanchor{path picture bounding box}{south west}}%
  \pgfmathsetmacro\fake@shading@step{\pgfkeysvalueof{/tikz/fakeshading/step}}}
\makeatother
\tikzset{every real fake shading/.append style={fakeshading/step=.05}}
\begin{document}
\begin{tikzpicture}
\path[fake shading]  (0,1) rectangle (5,2);
\path[real fake shading] (0,0) rectangle (5,1);
\end{tikzpicture}
\begin{tikzpicture}[fakeshading/function=100*((2*\x-1)^2)]% x² between (-1 and 1)
\path[fake shading]  (0,1) rectangle (5,2);
\path[real fake shading] (0,0) rectangle (5,1);
\end{tikzpicture}
\begin{tikzpicture}[fakeshading/function=50*(sin(2*\x*360)+1)]% (sin x between 0 and 4pi)
\path[fake shading]  (0,1) rectangle (5,2);
\path[real fake shading] (0,0) rectangle (5,1);
\end{tikzpicture}
\tikz\shade[real fake shading] (0,0) rectangle (3,1);
\begin{tikzpicture}
\shade[real fake shading={colorA=green, colorB=magenta}]
  (0, 0) coordinate (bl) rectangle ++(2.5, 1) coordinate (tr);

\fill[magenta] ([shift=(up:1)] bl) rectangle ++(1.25, -.25)
  ++ (down:.5) rectangle ++(1.25, -.25);
\shade[left color=green, right color=magenta]
  (bl) rectangle ++ (1.25, .25) coordinate (m);
\shade[left color=magenta, right color=green]
  (tr) rectangle ++ (-1.25, -.25);
\end{tikzpicture}
\end{document}

输出

fake shading转换后看起来不太好,并且有一些瑕疵。

在此处输入图片描述

没有real fake shading同样的问题:

在此处输入图片描述 在此处输入图片描述

相关内容