仅在间谍放大镜中绘图

仅在间谍放大镜中绘图

我希望能够在间谍放大镜中绘制某些内容,而不将其绘制在主图片中(例如,仅在放大的图片版本中添加特定注释)。

为什么这不是重复的?

相关话题:

我想要实现的目标

理想情况下,我想在放大的绘图部分上指示某些内容,如下所示:

在此处输入图片描述

我设法用以下 MWE 制作了这个情节(灵感来自这个答案):

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{width=10cm, height=5cm, compat=1.18}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\usetikzlibrary{spy}

% Store magnification and lens size in macros
\newcommand\magn{2}
\newcommand\msize{3cm}

\pgfdeclarelayer{fg} % declare foreground layer
\pgfsetlayers{main, fg}
\def\pival{3.14159265359}

\begin{document}
    \begin{tikzpicture}[%
        spy using outlines={circle, magnification=\magn, size=\msize, connect spies}
        ]
        \begin{axis}[domain=0:2*\pival, ymin=0, ymax=1.2, xmin = 0, xmax=2*\pival, samples=17]
            \addplot {sin(x*180/\pival)};
            \coordinate (spyonto) at (axis cs:\pival/2,0.9);
            \coordinate (magloc) at (axis cs:5,0.6);
            \spy on (spyonto) in node at (magloc) [fill=white];
            \coordinate (arrowstart) at (axis cs:4.3,0.5);
            \coordinate (arrowend) at (axis cs:5.7, 0.5);
        \end{axis}
        \begin{pgfonlayer}{fg}
            \draw[Stealth-Stealth, red, thick] (arrowstart) -- (arrowend);
        \end{pgfonlayer}
    \end{tikzpicture}
\end{document}

然而,这并不令人满意,原因如下:

  • 箭头必须在axis环境之外绘制,这意味着如果我们想使用轴坐标,我们必须事先将它们声明为arrowstartarrowend
  • 箭头必须在专用图层内绘制,这并不切实际。
  • 必须根据大量参数(放大率和镜头尺寸、原始绘图坐标、放大镜位置)猜测/估计箭头坐标

另外,请记住,如果这些问题在这种精确情况下看起来像是一个小负担,那是因为它是一个涉及几个此类注释的复杂图形的过于简单的例子。

我探索的其他解决方案

使用所介绍的方法这里(注意小胡的评论),我得到了这个结果:

在此处输入图片描述

使用以下代码:

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{width=10cm, height=5cm, compat=1.18}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\usetikzlibrary{spy, calc}

% Store magnification and lens size in macros
\newcommand\magn{2}
\newcommand\msize{3cm}

\pgfdeclarelayer{fg} % declare foreground layer
\pgfsetlayers{main, fg}
\def\pival{3.14159265359}

\tikzstyle{only in spy node}=[%
transform canvas={%
    shift={($-\magn*(spyonto)+(magloc)$)},
    scale=\magn,
}
]

\begin{document}
    \begin{tikzpicture}[%
        spy using outlines={circle, magnification=\magn, size=\msize, connect spies}
        ]
        \begin{axis}[domain=0:2*\pival, ymin=0, ymax=1.2, xmin = 0, xmax=2*\pival, samples=17]
            \begin{scope}
                \addplot {sin(x*180/\pival)};
                \coordinate (spyonto) at (axis cs:\pival/2,0.9);
                \coordinate (magloc) at (axis cs:5,0.6);
                \spy on (spyonto) in node at (magloc);% [fill=white];
                \coordinate (arrowstart) at (axis cs:4.3,0.5);
                \coordinate (arrowend) at (axis cs:5.7, 0.5);
            \end{scope}
            \begin{scope}[only in spy node]
                % clip this scope to keep it inside the magnifier
                \clip (spyonto) circle ({(\msize/2-0.4pt)/\magn});
                \fill [green] (spyonto) circle (12pt);
                \fill [red] (spyonto) circle (2pt);
                \draw[Stealth-Stealth, red, thick] (1.2, 0.95) -- (2, 0.95);
            \end{scope}
        \end{axis}
    \end{tikzpicture}
\end{document}

这在某种程度上是更好的,因为:

  • 我们现在可以使用本机axis坐标来绘制注释(如果我们有想要准确指示的精确数据点,这很方便)
  • 我们不再使用单独的层

然而,这并没有完全发挥作用,因为注释现在在后面[fill=white];主图。这就是为什么注释掉的原因,如果取消注释,所有注释都会消失。我尝试使用以下方法将它们放在前景层中:

\begin{pgfonlayer}{fg}
    \clip (spyonto) circle ({(\msize/2-0.4pt)/\magn});
    \fill [green] (spyonto) circle (12pt);
    \fill [red] (spyonto) circle (2pt);
    \draw[Stealth-Stealth, red, thick] (1.2, 0.95) -- (2, 0.95);
\end{pgfonlayer}

但如果我这样做,它们也会出现在微缩图中:

在此处输入图片描述

这不是理想的行为。

我也看了那里但因为我们想在放大镜里面画一些东西,所以我们不想离开它的观察范围。

如果您有解决此问题的方法,我们将非常欢迎!:)

答案1

该解决方案的目标是

  • 无需处理间谍镜头选项,
  • 不使用画布转换进行注释,
  • 允许使用 PGFPlots 坐标系和
  • 能够在放大的图片的前后进行绘画。

为了这,

  • \tikz@lib@spy@do(这是完成所有事情的主要宏)被修补,以便在将侦测节点实际放到页面上之前找到它的位置,
  • \tikz@lib@spy@transformation在设置所需转换的注释之前添加宏。

之前背景背景背后spy-in 节点的路径用于绘制放大图片前后的内容(这实际上是一个path picture[带有 PGFpicture 的节点],因此是背景路径——对于大多数节点来说,这是唯一定义的路径)。

您的 TikZ 图片需要进行的更改如下:

  • 将间谍范围移至环境axis(间谍输入节点排版在间谍范围的末尾,这是我们访问 PGFPlots 坐标系的唯一机会),
  • 总是使用明确的坐标系(例如axis cs:
  • 并将一切与间谍命令有关的内容放入\pgfplotsextra

\spy本身并没有做太多事情,只是收集它的参数并将它们放入一个列表中,以便在范围结束时执行,但此时对于 PGFPlots 的一些魔力来说已经太晚了。我们需要直接使用“执行”间谍代码\pgfplotsextra


注释应该被剪裁吗?也许可以重写,\tikz@lib@spy@do但这是一个带有嵌套事物的转换节。我不知道并使用很多 PGFPlots 来深入研究这一点。

代码

\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\pgfplotsset{width=10cm, height=5cm, compat=1.18}
\usetikzlibrary{arrows.meta, spy, calc}
\makeatletter
\let\tikz@lib@spy@do@orig\tikz@lib@spy@do % sigh
\def\tikz@lib@spy@do#1#2#3{% Have to find the location of spyinnode w/o drawing
  \setbox\pgfutil@tempboxa\hbox{%
    \node[overlay,spy annotations fg/.code=,spy annotations bg/.code=,
      alias=tikzspyinnode]#3{};}%
  \tikz@lib@spy@do@orig{#1}{#2}{#3}}
\tikzset{
  spy annotations fg/.code={%
    \tikz@addoption{%
      \expandafter\edef\csname pgf@sh@fbg@\tikz@shape\endcsname{%
        \noexpand\tikz@lib@spy@transformation{\tikz@shape}%
        \pgfutil@unexpanded{#1}}}},
  spy annotations bg/.code={%
    \tikz@addoption{%
      \expandafter\edef\csname pgf@sh@bbg@\tikz@shape\endcsname{%
        \noexpand\tikz@lib@spy@transformation{\tikz@shape}%
        \pgfutil@unexpanded{#1}}}}}
\def\tikz@lib@spy@transformation#1{% what shape really uses these paths?
  \expandafter\let\csname pgf@sh@fbg@#1\endcsname\pgfutil@undefined % nesting
  \expandafter\let\csname pgf@sh@bbg@#1\endcsname\pgfutil@undefined % nesting
  \pgftransformreset
  \let\tikz@transform\relax
  \pgftransformshift{%
    \expandafter\tikzset\expandafter{\tikz@lib@spy@lens}%
    \pgftransforminvert
    \pgfpointdiff                     {\pgfpointanchor{tikzspyonnode}{center}}
                 {\pgfpointtransformed{\pgfpointanchor{tikzspyinnode}{center}}}}%
  \expandafter\tikzset\expandafter{\tikz@lib@spy@lens}}
\makeatother
\begin{document}
\begin{tikzpicture}[declare function={sind(\x)=sin(deg(\x));}]
\begin{axis}[
  domain=0:2*pi, ymin=0, ymax=1.2, xmin = 0, xmax=2*pi, samples=17,
  spy using outlines={circle, magnification=2, size=3cm, connect spies}]% ←
\addplot {sind(x)};
\pgfplotsextra{% ← !
  \coordinate (magloc) at (axis cs:5, 0.6); % needs axis cs:
  \spy on (axis cs:pi/2,0.9) in node at (magloc) [% needs axis cs:
    spy annotations fg={% these all need explicit cs:
      \draw[Stealth-Stealth, red, thick]
        (axis cs: pi/2-pi/8, {sind(pi/2-pi/8)}) -- +(axis direction cs: pi/4, 0);
    },
    spy annotations bg={% yeah, these too
      \fill [green] (axis cs: pi/2, .9) circle[radius=12pt];
      \fill [red]   (axis cs: pi/2, .9) circle[radius= 2pt];
      \node[below left, inner sep=+0pt, draw, dashed, overlay, align=center]
        at (tikzspyinnode) {I'm not clipped\\and also a circle.};
       %    tikzspyinnode only works because of the patch
    }
  ];
}
\end{axis}
\end{tikzpicture}
\end{document}

输出

在此处输入图片描述

答案2

瞧:

\documentclass{standalone}
\usepackage{pgfplots}
\pgfplotsset{width=10cm, height=5cm, compat=1.18}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\usetikzlibrary{spy, calc}

% Store magnification and lens size in macros
\newcommand\magn{2}
\newcommand\msize{3cm}

\pgfdeclarelayer{fg} % declare foreground layer
\pgfsetlayers{main, fg}
\def\pival{3.14159265359}

\tikzstyle{only in spy node}=[%
transform canvas={%
    shift={($-\magn*(spyonto)+(magloc)$)},
    scale=\magn,
}
]

\begin{document}
    \begin{tikzpicture}[spy using outlines={}]
      \begin{axis}[domain=0:2*\pival, ymin=0, ymax=1.2, xmin = 0, xmax=2*\pival, samples=17]
        \coordinate (spyonto) at (axis cs:\pival/2,0.9);
        \coordinate (magloc) at (axis cs:5,0.6);
        \coordinate (arrowstart) at (axis cs:4.3,0.5);
        \coordinate (arrowend) at (axis cs:5.7, 0.5);
        \begin{scope}[spy using outlines={circle, magnification=\magn, size=\msize, connect spies}]
          \addplot {sin(x*180/\pival)};
          \spy on (spyonto) in node at (magloc)[name=spynode];
        \end{scope}
        % Remplace pink par white, j'ai mis pink pour que tu te rendes mieux compte sur la figure.
        \fill [pink]  (magloc) circle (\msize/2);
        \begin{scope}[anchor=spyonto, transform canvas={%
            shift={($-\magn*(spyonto)+(magloc)$)},
            scale=\magn }]
          % clip this scope to keep it inside the magnifier
          \clip (spyonto) circle ({(\msize/2-0.4pt)/\magn});
          \fill [green] (spyonto) circle (12pt);
          \fill [red] (spyonto) circle (2pt);
          \draw[Stealth-Stealth, red, thick] (1.2, 0.95) -- (2, 0.95);
        \end{scope}
      \end{axis}
    \end{tikzpicture}
\end{document}

编译源代码

相关内容