我正在尝试重现以下图像:
为此,我创建了 3 个节点、一条支撑路径 ( mycurve
) 和 (隐藏) 支撑线 (l1
到l12
),然后将其他节点放置在lx
和mycurve
交叉点上。效果很好。
我正在尝试设置箭头。箭头的支撑线只是 的平移mycurve
。我使用平滑图来绘制箭头,但结果并不完美,尤其是对于没有中间绘制点的箭头(例如从 7 到 8)。
有没有办法使用之前绘制的支持曲线而不是使用绘图来绘制箭头?换句话说,我想沿着命名路径绘制一条从5.x
到的路径,而不是使用绘图(其他路径也一样)。8.x
mycurve3
提前致谢。
这是我的结果:
我的 MWE 来源如下:
\documentclass[preview]{standalone}
\usepackage{calc}
\usepackage{tikz}
\usetikzlibrary{calc}
\usetikzlibrary{intersections}
\tikzset{
degree/.style = {
circle,
draw,
fill=white,
},
l/.style = {
-latex,
line width = #1,
},
l1/.style = { l=1pt },
l2/.style = { l=2pt },
l3/.style = { l=3pt },
}
\begin{document}
\begin{tikzpicture}[xscale=1,
yscale=1]
\pgfdeclarelayer{nodes}
\pgfdeclarelayer{links}
\pgfsetlayers{main,links,nodes}
\begin{pgfonlayer}{main}
%% Create on each degree to intersect later with mycurve.
%% Each line is a named path from l1 to l12
\foreach \i in {1,...,12}{
\coordinate[] (l1-\i) at (0,\i/1.5);
\coordinate[] (l2-\i) at (3.5,\i/1.5);
\path[name path global=l\i] (l1-\i) -- (l2-\i);
}
\end{pgfonlayer}
\begin{pgfonlayer}{nodes}
\node[degree] (1) at (0, 0/1.5) {1};
\node[degree] (5) at (2, 7/1.5) {5};
\node[degree] (8) at (0, 12/1.5) {8};
\end{pgfonlayer}
\begin{pgfonlayer}{main}
\draw [line width=5pt,red!20,name path global=mycurve]
($ (8) + (0.0,0) $) to[out=-30,in=90]
($ (5) + (0.0,0) $) to[in=57,out=-90]
($ (1) + (0.0,0) $);
%% Create an intersection coordinate for each l1-l12 lines and mycurve
%% to place each degree. Each intersection point is named i1 to i12.
\def\mycurveIntersection#1{%
\path[name intersections={of=l#1 and mycurve}] (intersection-1) coordinate (i#1);
}
\foreach \i in {1,...,12}{
\mycurveIntersection\i
%%\fill[red] (i\i) circle (2pt);
}
\end{pgfonlayer}
\begin{pgfonlayer}{nodes}
\node[degree] (2) at (i2) {2};
\node[degree] (3) at (i4) {3};
\node[degree] (4) at (i5) {4};
\node[degree] (6) at (i9) {6};
\node[degree] (7) at (i11) {11};
%% Draw to arrows supports lines
\foreach \i in {1,2,3} {
\draw [red,name path global=mycurve\i]
($ (8) + (4-\i,0) $) to[out=-30,in=90]
($ (5) + (4-\i,0) $) to[in=57,out=-90]
($ (1) + (4-\i,0) $);
}
\end{pgfonlayer}
%% Draw the links
%%
%% TODO: find a better way using previously created mycurves 1-3.
\begin{pgfonlayer}{links}
\def\myshift{3}
\draw[l1,shorten <= 2pt] plot[smooth] coordinates{
($ (i7) + (\myshift,0)$)
($ (i8) + (\myshift,0) $)
($ (i9) + (\myshift,0) $)
($ (i10) + (\myshift,0) $)
($ (i11) + (\myshift,0) $)
($ (i12) + (\myshift,0) $)};
\draw[l1,shorten <= 2pt] plot[smooth] coordinates{
($ (i7) + (\myshift,0)$)
($ (i6) + (\myshift,0) $)
($ (i5) + (\myshift,0) $)
($ (i4) + (\myshift,0) $)
($ (i3) + (\myshift,0) $)
($ (i2) + (\myshift,0) $)
($ (i1) + (\myshift,0) $)
($ (1) + (\myshift,0) $)
};
\def\myshift{2}
\draw[l2,shorten <= 2pt] plot[smooth] coordinates{
($ (6) + (\myshift,0)$)
($ (i10) + (\myshift,0) $)
($ (i11) + (\myshift,0) $)
($ (8) + (\myshift,0) $)};
\draw[l2,shorten <= 2pt] plot[smooth] coordinates{
($ (6) + (\myshift,0)$)
($ (i8) + (\myshift,0) $)
($ (5) + (\myshift,0) $)};
\draw[l2,shorten <= 2pt] plot[smooth] coordinates{
($ (3) + (\myshift,0)$)
($ (i3) + (\myshift,0) $)
($ (2) + (\myshift,0) $)};
\def\myshift{1}
\draw[l3] plot[smooth] coordinates{
($ (2) + (\myshift,0)$)
($ (i1) + (\myshift,0)$)
($ (1) + (\myshift,0) $)
};
%% These ones are really not on the mycurves
\draw[l3] ($ (7) + (\myshift,0)$) -- ($ (8) + (\myshift,0)$);
\draw[l3] ($ (4) + (\myshift,0)$) -- ($ (3) + (\myshift,0)$);
\end{pgfonlayer}
%% Add extra line helpers for reading
\begin{pgfonlayer}{main}
\draw[dashed] (1) -- (8);
\draw[dashed] ($ (i7) + (3,0) $) -- ($ (1)!(i7)!(8) $);
\draw[dashed] ($ (i9) + (2,0) $) -- ($ (1)!(i9)!(8) $);
\draw[dashed] ($ (i4) + (2,0) $) -- ($ (1)!(i4)!(8) $);
\draw[dashed] ($ (i5) + (1,0) $) -- ($ (1)!(i5)!(8) $);
\draw[dashed] ($ (i2) + (1,0) $) -- ($ (1)!(i2)!(8) $);
\draw[dashed] ($ (i11) + (1,0) $) -- ($ (1)!(i11)!(8) $);
\end{pgfonlayer}
\end{tikzpicture}
\end{document}
答案1
这不是一个完整的答案,因为它需要一些反馈。主要信息是:
是的,有一种方法可以重新绘制任意路径的交叉段。
fillbetween
这可以通过 (!)库来实现pgfplots
。应用于您不满意的路径,使用这些路径可获得
这是代码,它们用以下类型的命令绘制
\RedrawSegment[l3]{3}{5}{4}
其中可选参数是线条样式,第一个是级别,另外两个是要计算交点的线条。
\documentclass[preview]{standalone}
\usepackage{pgfplots}
\usetikzlibrary{calc} % ,bending would look better but clashes with the way you
% construct your paths
\usepgfplotslibrary{fillbetween}
\tikzset{
degree/.style = {
circle,
draw,
fill=white,
},
l/.style = {
-latex,
line width = #1,
},
l1/.style = { l=1pt },
l2/.style = { l=2pt },
l3/.style = { l=3pt },
}
\begin{document}
\begin{tikzpicture}[xscale=1,
yscale=1]
\pgfdeclarelayer{nodes}
\pgfdeclarelayer{links}
\pgfsetlayers{main,links,nodes}
\begin{pgfonlayer}{main}
%% Create on each degree to intersect later with mycurve.
%% Each line is a named path from l1 to l12
\foreach \i in {1,...,12}{
\coordinate[] (l1-\i) at (0,\i/1.5);
\coordinate[overlay] (l2-\i) at (10,\i/1.5);
\path[overlay,name path global=l\i] (l1-\i) -- (l2-\i);
}
\end{pgfonlayer}
\begin{pgfonlayer}{nodes}
\node[degree] (1) at (0, 0/1.5) {1};
\node[degree] (5) at (2, 7/1.5) {5};
\node[degree] (8) at (0, 12/1.5) {8};
\end{pgfonlayer}
\begin{pgfonlayer}{main}
\draw [line width=5pt,red!20,name path global=mycurve]
(0, 12/1.5) to[out=-30,in=90]
(2, 7/1.5) to[in=57,out=-90]
(0, 0/1.5);
\end{pgfonlayer}
%% Create an intersection coordinate for each l1-l12 lines and mycurve
%% to place each degree. Each intersection point is named i1 to i12.
\foreach \i in {1,...,12}{
\path[name intersections={of={l\i} and mycurve}] (intersection-1) coordinate
(i\i);
%%\fill[red] (i\i) circle (2pt);
}
\begin{pgfonlayer}{nodes}
\node[degree] (2) at (i2) {2};
\node[degree] (3) at (i4) {3};
\node[degree] (4) at (i5) {4};
\node[degree] (6) at (i9) {6};
\node[degree] (7) at (i11) {11};
%% Draw to arrows supports lines
\foreach \i in {1,2,3} {
\draw [red,name path global=mycurve\i]
($ (8) + (4-\i,0) $) to[out=-30,in=90]
($ (5) + (4-\i,0) $) to[in=57,out=-90]
($ (1) + (4-\i,0) $);
}
\end{pgfonlayer}
%% Draw the links
%%
%% TODO: find a better way using previously created mycurves 1-3.
\begin{pgfonlayer}{links}
\begin{scope}[every path/.append style={shorten <= 2pt}]
\def\myshift{3}
\draw[l1,shorten <= 2pt] plot[smooth] coordinates{
($ (i7) + (\myshift,0)$)
($ (i8) + (\myshift,0) $)
($ (i9) + (\myshift,0) $)
($ (i10) + (\myshift,0) $)
($ (i11) + (\myshift,0) $)
($ (i12) + (\myshift,0) $)};
\draw[l1,shorten <= 2pt] plot[smooth] coordinates{
($ (i7) + (\myshift,0)$)
($ (i6) + (\myshift,0) $)
($ (i5) + (\myshift,0) $)
($ (i4) + (\myshift,0) $)
($ (i3) + (\myshift,0) $)
($ (i2) + (\myshift,0) $)
($ (i1) + (\myshift,0) $)
($ (1) + (\myshift,0) $)
};
\def\myshift{2}
\draw[l2,shorten <= 2pt] plot[smooth] coordinates{
($ (6) + (\myshift,0)$)
($ (i10) + (\myshift,0) $)
($ (i11) + (\myshift,0) $)
($ (8) + (\myshift,0) $)};
\draw[l2,shorten <= 2pt] plot[smooth] coordinates{
($ (6) + (\myshift,0)$)
($ (i8) + (\myshift,0) $)
($ (5) + (\myshift,0) $)};
\draw[l2,shorten <= 2pt] plot[smooth] coordinates{
($ (3) + (\myshift,0)$)
($ (i3) + (\myshift,0) $)
($ (2) + (\myshift,0) $)};
\def\myshift{1}
\draw[l3] plot[smooth] coordinates{
($ (2) + (\myshift,0)$)
($ (i1) + (\myshift,0)$)
($ (1) + (\myshift,0) $)
};
%% These ones are really not on the mycurves
% \draw[l3] ($ (7) + (\myshift,0)$) -- ($ (8) + (\myshift,0)$);
% \draw[l3] ($ (4) + (\myshift,0)$) -- ($ (3) + (\myshift,0)$);
\draw[l3, intersection segments={of=l2 and mycurve3,sequence=R2}];
\newcommand{\RedrawSegment}[4][]{
\ifnum#3>#4
\path[name path=aux,
intersection segments={of=l#3 and mycurve#2,sequence=R2}];
\draw[#1, intersection segments={of=l#4 and aux,sequence=R1}];
\else
\path[name path=aux,
intersection segments={of=l#3 and mycurve#2,sequence=R1}];
\draw[#1, intersection segments={of=l#4 and aux,sequence={R1}}];
\fi }
\RedrawSegment[l3]{3}{5}{4}
\RedrawSegment[l3,latex-]{3}{10}{11}
%\RedrawSegment[l2]{2}{4}{2}
%\RedrawSegment[l2,blue]{2}{9}{7}
\end{scope}
\end{pgfonlayer}
%% Add extra line helpers for reading
\begin{pgfonlayer}{main}
\draw[dashed] (1) -- (8);
\draw[dashed] ($ (i7) + (3,0) $) -- ($ (1)!(i7)!(8) $);
\draw[dashed] ($ (i9) + (2,0) $) -- ($ (1)!(i9)!(8) $);
\draw[dashed] ($ (i4) + (2,0) $) -- ($ (1)!(i4)!(8) $);
\draw[dashed] ($ (i5) + (1,0) $) -- ($ (1)!(i5)!(8) $);
\draw[dashed] ($ (i2) + (1,0) $) -- ($ (1)!(i2)!(8) $);
\draw[dashed] ($ (i11) + (1,0) $) -- ($ (1)!(i11)!(8) $);
\end{pgfonlayer}
\end{tikzpicture}
\end{document}
如您所见,我没有完全重写代码。这有两个原因。其中一个原因是,按照您当前构建路径的方式,这可能会导致dimension too large
错误。(这并非特定于重绘,如果您要在相应区域中装饰路径,它们也会显示出来。)第二个原因是我不理解您的某些构造,例如类型的块($ (i7) + (\myshift,0)$)
,我相信可以将其做得更短。
答案2
使用@marmot 的答案几乎有效。
我可以轻松地将其用于RedrawSegment
所有路径。
以下是代码:
\begin{pgfonlayer}{main}
%% Create on each degree to intersect later with mycurve.
%% Each line is a named path from l1 to l12
\foreach \i in {0,...,12}{
\coordinate[] (l1-\i) at (0,\i/1.5);
\coordinate[overlay] (l2-\i) at (10,\i/1.5);
\path[overlay,name path global=l\i] (l1-\i) -- (l2-\i);
}
\end{pgfonlayer}
[...]
\begin{pgfonlayer}{links}
\newcommand{\RedrawSegment}[4][]{%
\ifnum#3>#4%
\path[name path=aux,%
intersection segments={of=l#3 and mycurve#2,sequence=R2}];%
\draw[#1, intersection segments={of=l#4 and aux,sequence=R1}];%
\else%
\path[name path=aux,%
intersection segments={of=l#3 and mycurve#2,sequence=R1}];%
\draw[#1, intersection segments={of=l#4 and aux,sequence={R1}}];%
\fi}%
%% Shorten on this path does not seem to work correctly.
\RedrawSegment[l1,latex-,shorten >= 10pt]{1}{12}{7}
\RedrawSegment[l1,shorten <= 2pt]{1}{7}{0}
\RedrawSegment[l2,latex-,shorten >= 2pt]{2}{12}{9}
%% For some reason the arrow on this one is not correctly drawn. But
%% if we draw to {6} it works nicely. Maybe because {7} is a junction
%% point?
\RedrawSegment[l2,-latex,shorten <= 2pt]{2}{9}{7}
\RedrawSegment[l2]{2}{4}{2}
%% No apparent issue on this one
\RedrawSegment[l3]{3}{5}{4}
\RedrawSegment[l3,latex-]{3}{10}{11}
\RedrawSegment[l3]{3}{2}{0}
\end{pgfonlayer}
结果比情节版本好得多。然而仍然存在一些问题:
- 从 6 到 5 的箭头绘制不正确。路径与箭头尖端重叠。
- 5到8的箭头不能缩短。