pgfplots
我正在尝试通过库查找路径与图的交点intersection
。找到的交点显然与可见交点不匹配。它们似乎被转换到了不同的坐标系。是否可以正确计算这些交点?
平均能量损失
\documentclass{article}
\usepackage{pgfplots, tikz}
\usetikzlibrary{calc, intersections}
\begin{document}
\begin{tikzpicture}
\begin{axis}[name=firstaxis]
\addplot[name path global=firstfunction]{e^x};
\end{axis}
\begin{axis}[name=secondaxis, at={($(firstaxis.south)-(0,1cm)$)}, anchor=north]
\addplot[name path global=secondfunction]{x^3};
\end{axis}
% Draw intersection line
\draw[color=black, opacity=1, name path global=intersectionline] (firstaxis.north) -- (secondaxis.south);
% Draw intersections points
\fill
[name intersections={of=intersectionline and firstfunction}]
(intersection-1) circle (2pt);
\fill
[name intersections={of=intersectionline and secondfunction}]
(intersection-1) circle (2pt);
\end{tikzpicture}
\end{document}
答案1
我希望有更简单的方法来做到这一点但是......
首先,据我了解,PGFPlots 会计算绘图点,将绘制的路径放在轴框中,然后将轴框定位在图片中。将轴框移动到所需位置不会改变使用name path
交叉库中的键获得的底层低级 PGF 路径表示的坐标。
axis
如果在第二个环境之后直接手动绘制(红色)保存的绘制路径,则可以看到这一点:
\documentclass[border=0.125cm]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{calc,intersections}
\tikzset{
name path global/.append code={%
\csname tikz@addmode\endcsname{%
\pgfgetpath\tmp%
\expandafter\global\expandafter\let\csname tikz@intersect@path@name@#1\endcsname=\tmp%
}%
}%
}
\begin{document}
\begin{tikzpicture}
\begin{axis}
[
name=firstaxis,
domain=-5:5,
xmin=-6, xmax=6,
ymin=-10, ymax=160,
enlargelimits=false
]
\addplot[name path global=firstfunction]{e^x};
\end{axis}
\begin{axis}
[
name=secondaxis,
domain=-5:5,
xmin=-6, xmax=6,
ymin=-150, ymax=150,
enlargelimits=false,
at={($(firstaxis.south)-(0,1cm)$)},
anchor=north
]
\addplot[name path global=secondfunction]{x^3};
\end{axis}
\expandafter\pgfsetpath\csname tikz@intersect@path@name@secondfunction\endcsname
\pgfsetstrokecolor{red}
\pgfusepath{stroke}
\end{tikzpicture}
\end{document}
第二个问题是,该name path global
密钥目前无法与 PGFPLots 正常配合使用,必须被黑客入侵(如上面的代码所示)。
这意味着尝试做你想做的事是可能的,但却非常麻烦。概念上最简单的方法是改变底层绘制的路径,但这对于复杂的绘图来说会很耗时,而且会涉及很多低级的东西。
在下面的方法中,必须将坐标intersectionline
移至任何不在原点的轴的“坐标系”。然后,交点也必须移位。
这(有点简单)但你还必须使用enlargelimits=false
(它的作用类似于一种“边距”)然后手动设置 |x| 和 |y| 轴的限制两个都斧头。
此外,name path global
密钥需要破解一点。这是一项相当繁重的工作,我怀疑其他一些不涉及交叉点的解决方法很多更轻松:
\documentclass[border=0.125cm]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{calc,intersections}
\tikzset{
name path global/.append code={%
\csname tikz@addmode\endcsname{%
\pgfgetpath\tmp%
\expandafter\global\expandafter\let\csname tikz@intersect@path@name@#1\endcsname=\tmp%
}%
}%
}
\begin{document}
\begin{tikzpicture}
\begin{axis}
[
name=firstaxis,
domain=-5:5,
xmin=-6, xmax=6,
ymin=-10, ymax=160,
enlargelimits=false
]
\addplot[name path global=firstfunction]{e^x};
\end{axis}
\begin{axis}
[
name=secondaxis,
domain=-5:5,
xmin=-6, xmax=6,
ymin=-150, ymax=150,
enlargelimits=false,
at={($(firstaxis.south)-(0,1cm)$)},
anchor=north
]
\addplot[name path global=secondfunction]{x^3};
\end{axis}
\foreach \col/\from/\to in {red/west/east, green/north/south, blue/north west/south east}{
% Draw intersection line
\draw
[color=\col, opacity=1, name path global=intersectionline]
(firstaxis.\from) -- (secondaxis.\to);
% Draw intersections points
\fill
[\col, name intersections={of=intersectionline and firstfunction}]
(intersection-1) circle [radius=2pt];
% Create the intersectionline in the secondaxis coordinate system.
\path [overlay] let \p1=(secondaxis.south west) in
[name path global=intersectionline]
([shift={(-\x1,-\y1)}]firstaxis.\from) -- ([shift={(-\x1,-\y1)}]secondaxis.\to);
% Draw the intersection point
\fill
[\col, name intersections={of=intersectionline and secondfunction}]
($(secondaxis.south west)+(intersection-1)$) circle [radius=2pt];
}
\end{tikzpicture}
\end{document}
好的,所以也可以用困难的方式完成。下面定义的宏\pgfpathretransform
“重新转换”低级 PGF 路径。可以使用密钥使用结果,transform named path
这样交叉点就不那么混乱了。
\documentclass[border=0.125cm]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{calc,intersections}
\makeatletter
\tikzset{
name path global/.append code={%
\tikz@addmode{%
\pgfgetpath\tmp%
\expandafter\global\expandafter\let\csname tikz@intersect@path@name@#1\endcsname=\tmp%
}%
},
transform named path/.code args={#1 by #2}{
\expandafter\let\expandafter\@tmp\csname tikz@intersect@path@name@#1\endcsname%
\pgfpathretransform{\tikzset{#2}\tikz@transform}{\@tmp}{\@tmp}%
\pgfinterruptpath%
\path[name path=#1]\pgfextra{\pgfsetpath\@tmp};
\endpgfinterruptpath%
}
}
% This macro 're-transforms' a soft-path
%
% #1 Pgf level transformation code
% #2 a macro containing the original soft path
% #3 a macro to store the transformed path
%
\def\pgfpathretransform#1#2#3{%
% First get the transform...
\begingroup%
\pgftransformreset%
#1%
\pgfgettransform\pgfpath@retransform%
\expandafter
\endgroup%
\expandafter\def\expandafter\pgfpath@retransform\expandafter{\pgfpath@retransform}%
\global\let\pgfpath@retransform@path=\pgfutil@empty%
\begingroup%
\pgfprocessround{#2}{#2}%
% Locally redefine the soft-path tokens so that they do most of the work.
\def\pgfsyssoftpath@movetotoken{\pgfpath@retransform@point{moveto}}%
\def\pgfsyssoftpath@linetotoken{\pgfpath@retransform@point{lineto}}%
\def\pgfsyssoftpath@curvetosupportatoken{\pgfpath@retransform@point{curvetosupporta}}%
\def\pgfsyssoftpath@curvetosupportbtoken{\pgfpath@retransform@point{curvetosupportblineto}}%
\def\pgfsyssoftpath@curvetotoken{\pgfpath@retransform@point{curveto}}%
\def\pgfsyssoftpath@rectcornertoken{\pgfpath@retransform@point{rectcorner}}%
\def\pgfsyssoftpath@rectsizetoken{\pgfpath@retransform@point{rectsize}}%
\def\pgfsyssoftpath@closepathtoken{\pgfpath@retransform@point{closepath}}%
#2%
\endgroup%
% Now \pgfpath@retransform@path holds the transformed path
\let#3=\pgfpath@retransform@path%
}
\def\pgfpath@retransform@point#1#2#3{%
\pgf@process{%
\pgf@x=#2\relax%
\pgf@y=#3\relax%
\pgfsettransform\pgfpath@retransform%
\pgf@pos@transform{\pgf@x}{\pgf@y}%
}%
\edef\pgf@marshal{\expandafter\noexpand\csname pgfsyssoftpath@#1token\endcsname{\the\pgf@x}{\the\pgf@y}}%
\expandafter\pgfutil@g@addto@macro\expandafter{\expandafter\pgfpath@retransform@path\expandafter}\expandafter{\pgf@marshal}%
}
\begin{document}
\begin{tikzpicture}
\begin{axis}
[
name=firstaxis,
domain=-5:5,
xmin=-6, xmax=6,
ymin=-10, ymax=160,
enlargelimits=false
]
\addplot[name path global=firstfunction]{e^x};
\end{axis}
\begin{axis}
[
name=secondaxis,
domain=-5:5,
xmin=-6, xmax=6,
ymin=-150, ymax=150,
enlargelimits=false,
at={($(firstaxis.south)-(0,1cm)$)},
anchor=north
]
\addplot[name path global=secondfunction]{x^3};
\end{axis}
% Transform the named path.
\tikzset{transform named path=secondfunction by {shift=(secondaxis.south west)}}
\foreach \col/\from/\to in {red/west/east, green/north/south, blue/north west/south east}{
% Draw intersection line
\draw
[color=\col, opacity=1, name path global=intersectionline]
(firstaxis.\from) -- (secondaxis.\to);
% Draw intersections points
\fill
[\col, name intersections={of=intersectionline and firstfunction}]
(intersection-1) circle [radius=2pt];
\fill
[\col, name intersections={of=intersectionline and secondfunction}]
(intersection-1) circle [radius=2pt];
}
\end{tikzpicture}
\end{document}
结果和以前一样。