更新

更新

我正在寻找一种使用 TikZ 绘制以下图片的简单方法。也就是说,我只想指定城市的坐标,然后使用循环通过边将它们连接起来\foreach。如果此图片上没有有向边,这将很容易:

在此处输入图片描述

因此,更准确地说,我的问题是如何修改\foreach下面的第二张图片以获得上面的图片。

\begin{scope}
\foreach \x/\y/\name/\label/\where in {1.2/1.4/a/{El Paso}/below,     
   1/3.2/b/Albuquerque/above, 2.5/3/c/Amarillo/below, 3.8/4/d/Wichita/above,  
   4.3/3.3/e/Tulsa/45, 5.2/2.8/f/{Little Rock}/right, 4.2/2/g/Dallas/left, 
   4.8/1/h/Houston/right, 3.6/0.6/i/{San Antonio}/below} {
  \draw (\x,\y) circle (.4mm);
\node[draw,circle,minimum size=2mm,inner sep=0mm,label=\where:{\footnotesize \label}] (\name) at (\x,\y) {};
}

\foreach \s/\t in {a/b, b/c, c/e, e/d, e/f, f/g, h/g, h/i}
  \path[draw] (\s) edge (\t);
\end{scope}

答案1

如果您创建一个简单的“装饰”,即从起始点到终止点绘制一条笔划,则可以使用raise装饰路径选项来获得平行路径。将shorten >shorten <应用于此凸起路径,并在其上放置箭头,即可获得所需的结果:

结果

以下是代码(样式parallel arrow涵盖所有内容):

\documentclass{article}
\usepackage{tikz}
\begin{document}
\usetikzlibrary{decorations}
\pgfdeclaredecoration{sl}{initial}{
  \state{initial}[width=\pgfdecoratedpathlength-1sp]{
     \pgfmoveto{\pgfpointorigin}
  }
  \state{final}{
     \pgflineto{\pgfpointorigin}
    }
}

\tikzset{parallel arrow/.style={->, 
     shorten >=2mm, shorten <=2mm, 
     decoration={sl,raise=1mm},decorate}}

\begin{tikzpicture}
\begin{scope}
\foreach \x/\y/\name/\label/\where in {1.2/1.4/a/{El Paso}/below,     
   1/3.2/b/Albuquerque/above, 2.5/3/c/Amarillo/below, 3.8/4/d/Wichita/above,  
   4.3/3.3/e/Tulsa/45, 5.2/2.8/f/{Little Rock}/right, 4.2/2/g/Dallas/left, 
   4.8/1/h/Houston/right, 3.6/0.6/i/{San Antonio}/below} {
  \draw (\x,\y) circle (.4mm);
\node[draw,circle,minimum size=2mm,inner sep=0mm,label=\where:{\footnotesize \label}] (\name) at (\x,\y) {};
}

\foreach \s/\t in {a/b, b/c, c/e, e/d, e/f, f/g, h/g, h/i} {
  \path[draw] (\s) edge (\t);
  \path[draw] (\s) edge[parallel arrow] (\t);
  \path[draw] (\t) edge[parallel arrow] (\s);}
\end{scope}
\end{tikzpicture}
\end{document}

更新

我给每条路线添加了数字。我很有趣地对它们的位置进行了参数化,以便将它们全部放在一个循环中。

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations,calc}
\begin{document}
\pgfdeclaredecoration{sl}{initial}{
  \state{initial}[width=\pgfdecoratedpathlength-1sp]{
     \pgfmoveto{\pgfpointorigin}
  }
  \state{final}{
     \pgflineto{\pgfpointorigin}
    }
}
\tikzset{parallel arrow/.style={latex-,
     shorten >=2mm, shorten <=2mm, 
     decoration={sl,raise=1mm},decorate}}

\begin{tikzpicture}
\begin{scope}
\foreach \x/\y/\name/\label/\where in {1.2/1.4/a/{El Paso}/below,     
   1/3.2/b/Albuquerque/above, 2.5/3/c/Amarillo/below, 3.8/4/d/Wichita/above,  
   4.3/3.3/e/Tulsa/45, 5.2/2.8/f/{Little Rock}/right, 4.2/2/g/Dallas/left, 
   4.8/1/h/Houston/right, 3.6/0.6/i/{San Antonio}/below} {
  \draw (\x,\y) circle (.4mm);
\node[draw,circle,minimum size=2mm,inner sep=0mm,label=\where:{\footnotesize \label}] (\name) at (\x,\y) {};
}

\tikzset{edge label/.style={font=\tiny, inner sep=1.6mm},
ab/.style={edge label, left},
ba/.style={edge label, right},
bc/.style={edge label, above},
cb/.style={edge label, below},
ce/.style={bc},
ec/.style={cb},
ed/.style={ab},
de/.style={ba},
ef/.style={edge label, below left, inner sep=1mm},
fe/.style={edge label, above right, inner sep=1mm},
fg/.style={edge label, above left, inner sep=1mm},
gf/.style={edge label, below right, inner sep=1mm},
hg/.style={ab},
gh/.style={ba},
hi/.style={bc},
ih/.style={cb}
}  

\foreach \s/\t/\from/\to in {a/b/9/10, b/c/8/11, c/e/7/12, e/d/6/5, 
                             e/f/13/4, f/g/14/3, h/g/15/2, h/i/16/1} {
  \path[draw] (\s) edge (\t) ($(\s)!.5!(\t)$) node[\s\t] {\from} node[\t\s]{\to};
  \path[draw] (\s) edge[parallel arrow] (\t);
  \path[draw] (\t) edge[parallel arrow] (\s);
}
\end{scope}
\end{tikzpicture}
\end{document}

结果

答案2

JLDiaz 的回答非常好,这只是一点补充:

我想避免对有向边的值进行硬编码,因此我想使用auto放置选项,将节点放置在路径的一侧。然而,事实证明这只发生在 45 度步骤中:节点要么使用其south锚点放置,要么使用其north west锚点等放置,但没有中间值。对于此应用程序,这还不够精确。但是,如果您重新定义两个内部函数,则可以获得节点的度数精度放置:

\makeatletter
\def\tikz@auto@anchor{%
    \pgfmathtruncatemacro\angle{atan2(\pgf@x,\pgf@y)-90}
    \edef\tikz@anchor{\angle}%
}

\def\tikz@auto@anchor@prime{%
    \pgfmathtruncatemacro\angle{atan2(\pgf@x,\pgf@y)+90}
    \edef\tikz@anchor{\angle}%
}
\makeatother

为了使标签与中心线的偏移均匀,我使用了ellipse节点形状。

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations,calc, shapes.geometric}

\makeatletter
\def\tikz@auto@anchor{%
    \pgfmathtruncatemacro\angle{atan2(\pgf@x,\pgf@y)-90}
    \edef\tikz@anchor{\angle}%
}

\def\tikz@auto@anchor@prime{%
    \pgfmathtruncatemacro\angle{atan2(\pgf@x,\pgf@y)+90}
    \edef\tikz@anchor{\angle}%
}
\makeatother

\begin{document}
\pgfdeclaredecoration{sl}{initial}{
  \state{initial}[width=\pgfdecoratedpathlength-1sp]{
     \pgfmoveto{\pgfpointorigin}
  }
  \state{final}{
     \pgflineto{\pgfpointorigin}
    }
}
\tikzset{parallel arrow/.style={latex-,
     shorten >=2mm, shorten <=1mm, 
     decoration={sl,raise=1mm},decorate}}

\begin{tikzpicture}
\begin{scope}
\foreach \x/\y/\name/\label/\where in {1.2/1.4/a/{El Paso}/below,     
   1/3.2/b/Albuquerque/above, 2.5/3/c/Amarillo/below, 3.8/4/d/Wichita/above,  
   4.3/3.3/e/Tulsa/30, 5.2/2.8/f/{Little Rock}/right, 4.2/2/g/Dallas/left, 
   4.8/1/h/Houston/right, 3.6/0.6/i/{San Antonio}/below} {
  \draw (\x,\y) circle (.4mm);
\node[draw,circle,minimum size=2mm,inner sep=0mm,label=\where:{\footnotesize \label}] (\name) at (\x,\y) {};
}

\tikzset{
    edge label/.style={
        font=\tiny,
        auto=right,
        ellipse,inner sep=1mm,
    }
}  

\foreach \s/\t/\from/\to in {a/b/9/10, b/c/8/11, c/e/7/12, e/d/6/5, 
                             e/f/13/4, f/g/14/3, h/g/15/2, h/i/16/1} {
  \path[draw] (\s) edge (\t);
  \path[draw] (\s) edge[parallel arrow]
    node [edge label] {\from} (\t);
  \path[draw] (\t) edge[parallel arrow]
  node [edge label] {\to}(\s);
}
\end{scope}
\end{tikzpicture}
\end{document}

答案3

这是使用库的另一种to path方法calc

一条边及其带有标签的平行箭头通过单一操作绘制to

\draw (from) to[edge with values=XX and YY] (to);

(其中XXYY从->到至->从标签。它们会自动定位。 在此处输入图片描述

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}
\tikzset{
  % store of parameters
  parallel distance/.store in=\paradist,
  parallel shorten/.store in=\parashorten,
  parallel label distance/.store in=\paralabdist,
  % default values
  parallel distance=1mm, % distance of parallel arrows from link
  parallel shorten=3mm, % to shorten parallel arrows
  parallel label distance=2.5mm, % distance of label from link
  % main style
  edge with values/.style args={#1 and #2}{
    to path={
      \pgfextra{
        \pgfinterruptpath
        % middle point
        \coordinate (m) at ($(\tikztostart)!.5!(\tikztotarget)$);
        % from-to arrow
        \draw[-stealth,shorten >=\parashorten,shorten <=\parashorten]
        ($(\tikztostart)!\paradist!-90:(\tikztotarget)$)
        --
        ($(\tikztotarget)!\paradist!90:(\tikztostart)$)
        % middle of from-to arrow
        coordinate[pos=.5](m from);
        % label of from-to arrow
        \node[font=\tiny] at ($(m)!\paralabdist!(m from)$){#1};
        % to-from arrow
        \draw[-stealth,shorten >=\parashorten,shorten <=\parashorten]
        ($(\tikztotarget)!\paradist!-90:(\tikztostart)$)
        --
        ($(\tikztostart)!\paradist!90:(\tikztotarget)$)
        % middle of to-from arrow
        coordinate[pos=.5](m to);
        % label of to-from arrow
        \node[font=\tiny] at ($(m)!\paralabdist!(m to)$){#2};
        \endpgfinterruptpath
      }
      % link
      (\tikztostart) -- (\tikztotarget)
    },
  },
}

\begin{document}
\begin{tikzpicture}
  \begin{scope}
    \foreach \x/\y/\name/\label/\where in {%
      1.2/1.4/a/{El Paso}/below,%     
      1/3.2/b/Albuquerque/above,%
      2.5/3/c/Amarillo/below,%
      3.8/4/d/Wichita/above,%
      4.3/3.3/e/Tulsa/45,%
      5.2/2.8/f/{Little Rock}/right,%
      4.2/2/g/Dallas/left,%
      4.8/1/h/Houston/right,%
      3.6/0.6/i/{San Antonio}/below%
    } {
      \draw (\x,\y) circle (.4mm);
      \node[draw,circle,minimum size=2mm,inner sep=0mm,
      label=\where:{\footnotesize \label}]
      (\name) at (\x,\y) {};
    }

    \foreach \s/\t/\from/\to in {
      a/b/10/9,
      b/c/11/8,
      c/e/12/7,
      e/d/5/6, 
      e/f/13/4,
      f/g/14/3,
      h/g/2/15,
      h/i/16/1
    } {
      \path[draw] (\s) to[edge with values=\from{} and \to] (\t);
    }
  \end{scope}
\end{tikzpicture}
\end{document}

相关内容