我使用下面的代码,正如我曾经展示的那样这里,在图片上添加描述性标签:
\documentclass[margin=1cm]{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\node[anchor=south west,inner sep=0] (image) at (0,0) {\includegraphics[width=5cm]{airplane.png}};
\begin{scope}[x={(image.south east)},y={(image.north west)}]
% \draw[help lines, very thin, step=0.02] (0,0) grid (1,1);
% \draw[help lines,thin,xstep=.1,ystep=.1] (0,0) grid (1,1);
% \foreach \x in {0,1,...,9} { \node [anchor=north] at (\x/10,0) {0.\x}; }
% \foreach \y in {0,1,...,9} { \node [anchor=east] at (0,\y/10) {0.\y}; }
\draw[<-] (0.5,0.6) -- (0.7,1.1) node[above] {label above};
\draw[<-] (0.3,0.5) -- (0.4,-0.1) node[below] {label below};
\draw[<-] (0.7,0.6) -- (1.1,0.7) node[right] {label right};
\draw[<-] (0.1,0.7) -- (-0.1,0.8) node[left] {label left};
\end{scope}
\end{tikzpicture}
\end{document}
结果:
(我从这里)
如你所见,如果箭头结束于图像上方,我希望标签的定位是标签文本位于箭头上方;如果箭头结束于图像左侧,我希望标签文本位于箭头左侧,依此类推。指定结束坐标 x=-0.1(位于图像左侧)以及标签位置有点多余,因此node[left].
我想知道是否有可能自动执行此操作,只需指定起始坐标和结束坐标之一,以及方向(左、右、上、下),例如如下所示
\draw[<-] (0.1,0.7) node[left, y=0.8] {label left};
当然,这并不像我在这里写的那样有效,这只是一个例子。这应该将标签放在箭头的左侧,其端点位于 x=-0.1 和 y=0.8。
注意:我在 MWE 中注释掉的部分只是为了显示一些坐标网格来找到箭头的起始位置。
此外,标签还有另一个问题。请看下面的图片
其中一个标签中有字母 p(比基线稍微靠下一点),而另一个节点没有。结果是标签不在同一高度,这很丑陋。可以strut{}
在标签文本中使用 a 来修复此问题,例如
\draw[<-] (0.4,0.6) -- (0.7,1.1) node[above] {\strut{} aaa};
\draw[<-] (0.3,0.6) -- (0.4,1.1) node[above] {\strut{} paaaaa};
结果如下:
如何自动将支柱添加到标签文本中?或者应该移动 TikZ 标签的基线?
答案1
这不是真正的答案,只是为了展示可以轻松完成的事情。您可以定义一种样式,将图片框架中的点与外部点和标签连接起来,其中计算外部点和标签位置。样式的工作方式如下:
\draw[<-,lazy label={(0.3,0.4) with auto}];
其中您只需指定点和标签。
\documentclass[margin=1cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}[declare function={offset(\x)=sign(\x)*80pt/(abs(\x)+4pt);},
lazy label/.style args={#1 with #2}{
insert path={
let \p1=($#1-(0.5,0.5)$),\p2=#1,\n1={atan2(\y1,\x1)} in #1
\pgfextra{\pgfmathtruncatemacro{\ntest}{mod(8+\n1/90,4)}\xdef\ntest{\ntest}
%\typeout{#1:#2,\x1,\y1,\x2,\y2,\n1,\ntest}
}
\ifcase\ntest%
#1 -- (1.1,{\y2+offset(\y1)}) node[right] {#2}
\or
#1 -- ({\x2+offset(\x1)},1.1) node[above] {#2}
\or
#1 -- (-0.1,{\y2+offset(\y1)}) node[left] {#2}
\or
#1 -- ({\x2+offset(\x1)},-0.1) node[below] {#2}
\fi
}}]
\node[anchor=south west,inner sep=0] (image) at (0,0)
{\includegraphics[width=5cm]{example-image-duck}};
\begin{scope}[x={(image.south east)},y={(image.north west)}]
\draw[<-,lazy label={(0.3,0.4) with auto}];
\end{scope}
\end{tikzpicture}
\end{document}
我还想提一下,如果你在循环中使用此样式,则需要注意扩展问题。然而,这些问题并不特定于样式,也出现在其他上下文中。
\documentclass[margin=1cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}[declare function={offset(\x)=sign(\x)*80pt/(abs(\x)+4pt);},
lazy label/.style args={#1 with #2}{
insert path={
let \p1=($#1-(0.5,0.5)$),\p2=#1,\n1={atan2(\y1,\x1)} in #1
\pgfextra{\pgfmathtruncatemacro{\ntest}{mod(8+\n1/90,4)}\xdef\ntest{\ntest}
%\typeout{#1:#2,\x1,\y1,\x2,\y2,\n1,\ntest}
}
\ifcase\ntest%
#1 -- (1.1,{\y2+offset(\y1)}) node[right] {#2}
\or
#1 -- ({\x2+offset(\x1)},1.1) node[above] {#2}
\or
#1 -- (-0.1,{\y2+offset(\y1)}) node[left] {#2}
\or
#1 -- ({\x2+offset(\x1)},-0.1) node[below] {#2}
\fi
}}]
\node[anchor=south west,inner sep=0] (image) at (0,0)
{\includegraphics[width=5cm]{example-image-duck}};
\begin{scope}[x={(image.south east)},y={(image.north west)}]
\foreach \X in {(0.5,0.6),(0.3,0.4),(0.7,0.6),(0.1,0.7)}
{
\edef\temp{\noexpand\draw[<-,lazy label={{\X} with auto}];}
\temp
}
\end{scope}
\end{tikzpicture}
\end{document}
到目前为止,一切都很好。但是这种样式不会检查新标签是否与已有标签发生冲突,也不会猜测您的想法,也就是说,在此版本中,您的标签below
不会按照您建议的方式完成,因为该点到上边界的距离较短。
答案2
我设法找到了一个可接受的解决方案,借助marmot 的回答。我使用了insert path
TikZ 的样式,如下所示:
\documentclass[border=1cm]{standalone}
\usepackage{tikz}
\tikzset{
lazy label below/.style args = {#1 at #2}{
red,
->,
insert path = {
(#2,-0.1) node[below] {#1 \strut{}}
}
},
lazy label above/.style args = {#1 at #2}{
red,
->,
insert path = {
(#2,1.1) node[above] {#1 \strut{}}
}
},
}
\begin{document}
\begin{tikzpicture}
\node[anchor=south west,inner sep=0] (image) at (0,0) {\includegraphics[width=5cm]{example-image}};
\begin{scope}[x={(image.south east)},y={(image.north west)}]
\draw[lazy label below={label text at 0.3}] to (0.2,0.2);
\draw[lazy label above={other text at 0.6}] to (0.4,0.8);
\end{scope}
\end{tikzpicture}
\end{document}
结果:
它允许我根据需要将标签放置在图像上方或下方,并相应地设置箭头起点的坐标。此外,它还会将添加到\strut{}
标签文本中,以确保所有标签的高度相同。我将在我的tikz-imagelabels
包中使用它。