所以我想做一个这样的图表:
https://en.m.wikipedia.org/wiki/Dijkstra%27s_algorithm#/media/File%3ADijkstra_Animation.gif
对于 djikstras 算法。不打算在 latex 中将其制作成动画,而希望制作成像这样的静态图像,但所有数字都在线上等等...
我已经在 tikz 中完成了一个,但代码太大,难以管理。有没有其他软件包可以让我以更少的代码绘制这样的节点图,从而更易于管理和更改图表?
代码1:
\documentclass[12pt, tikz, margin=3mm]{standalone}
\usetikzlibrary{arrows.meta, automata, positioning, quotes}
\begin{document}
\begin{tikzpicture}[
node distance = 22mm and 24mm,
every state/.append style = {inner sep=0pt, fill=gray!10,
minimum size=7mm},
every edge/.style = {draw, -Triangle, bend angle=15},
auto=right,
]
\node (s1) [state,fill=gray!50] {0};
\node (s2) [state, above right=of s1] {2};
\node (s3) [state, right=of s2] {$\infty$};
\node (s4) [state, below right=of s3] {$\infty$};
\node (s5) [state, below left=of s4] {$\infty$};
\node (s6) [state, left=of s5] {8};
%
\draw[gray!30, line width=5pt]
(s1) to (s2)
(s1) to [bend right=15] (s6);
%
\draw (s1) edge ["2"] (s2)
(s1) edge [bend right,"8"] (s6)
(s2) edge ["6"] (s3)
(s2) edge ["3"] (s5)
(s2) edge ["5"] (s6)
(s3) edge [out=135, in=90,looseness=1.5, "1"] (s1)
(s3) edge ["2"] (s4)
(s3) edge [bend right,"5"] (s5)
(s5) edge [bend right,"4"] (s3)
(s5) edge ["7"] (s4)
(s5) edge ["1"] (s6)
(s6) edge [bend right,"8"] (s1);
\end{tikzpicture}
\end{document}
代码2:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Welcome to Overleaf --- just edit your LaTeX on the left,
% and we'll compile it for you on the right. If you open the
% 'Share' menu, you can invite other users to edit at the same
% time. See www.overleaf.com/learn for more info. Enjoy!
%
% Note: you can export the pdf to see the result at full
% resolution.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\documentclass{beamer}
\usepackage{tikz}
\usepackage{verbatim}
\usetikzlibrary{arrows,shapes}
\begin{document}
\begin{comment}
:Title: Prim's algorithm
:Tags: Beamer, Layers, Foreach, Graphs
:Use page: 6
A step by step example of the `Prim's algorithm`_ for finding the `minimum
spanning tree`_. Animated using Beamer
overlays.
.. _Prim's algorithm: http://en.wikipedia.org/wiki/Prim%27s_algorithm
.. _Minimum spanning tree: http://en.wikipedia.org/wiki/Minimum_spanning_tree
| Source: Adapted from an example on Wikipedia_
.. _Wikipedia: http://en.wikipedia.org/wiki/Prim%27s_algorithm
\end{comment}
% Declare layers
\pgfdeclarelayer{background}
\pgfsetlayers{background,main}
\begin{frame}
\frametitle{Prim's algorithm}
%% Adjacency matrix of graph
%% \ a b c d e f g
%% a x 7 5
%% b 7 x 8 9 7
%% c 8 x 5
%% d 5 9 x 15 6
%% e 7 5 15 x 8 9
%% f 6 8 x 11
%% g 9 11 x
\tikzstyle{vertex}=[circle,fill=black!25,minimum size=20pt,inner sep=0pt]
\tikzstyle{selected vertex} = [vertex, fill=red!24]
\tikzstyle{edge} = [draw,thick,-]
\tikzstyle{weight} = [font=\small]
\tikzstyle{selected edge} = [draw,line width=5pt,-,red!50]
\tikzstyle{ignored edge} = [draw,line width=5pt,-,black!20]
\begin{figure}
\begin{tikzpicture}[scale=1.8, auto,swap]
% Draw a 7,11 network
% First we draw the vertices
\foreach \pos/\name in {{(0,2)/a}, {(2,1)/b}, {(4,1)/c},
{(0,0)/d}, {(3,0)/e}, {(2,-1)/f}, {(4,-1)/g}}
\node[vertex] (\name) at \pos {$\name$};
% Connect vertices with edges and draw weights
\foreach \source/ \dest /\weight in {b/a/7, c/b/8,d/a/5,d/b/9,
e/b/7, e/c/5,e/d/15,
f/d/6,f/e/8,
g/e/9,g/f/11}
\path[edge] (\source) -- node[weight] {$\weight$} (\dest);
% Start animating the vertex and edge selection.
\foreach \vertex / \fr in {d/1,a/2,f/3,b/4,e/5,c/6,g/7}
\path<\fr-> node[selected vertex] at (\vertex) {$\vertex$};
% For convenience we use a background layer to highlight edges
% This way we don't have to worry about the highlighting covering
% weight labels.
\begin{pgfonlayer}{background}
\pause
\foreach \source / \dest in {d/a,d/f,a/b,b/e,e/c,e/g}
\path<+->[selected edge] (\source.center) -- (\dest.center);
\foreach \source / \dest / \fr in {d/b/4,d/e/5,e/f/5,b/c/6,f/g/7}
\path<\fr->[ignored edge] (\source.center) -- (\dest.center);
\end{pgfonlayer}
\end{tikzpicture}
\end{figure}
\end{frame}
\end{document}
代码3:
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}
%------------------------------------------------------------------------------
%Introductory example
\begin{figure}[p]
\begin{tikzpicture}
\filldraw[black] (0,0) circle (2pt) node[anchor=west] {Intersection point};
\draw[gray, thick] (-1,2) -- (2,-4);
\draw[gray, thick] (-1,-1) -- (2,2);
\end{tikzpicture}
\end{figure}
%------------------------------------------------------------------------------
%------------------------------------------------------------------------------
%Points, lineas and curves
\begin{figure}[p]
\begin{tikzpicture}
\draw (-2,0) -- (2,0);
\filldraw [gray] (0,0) circle (2pt);
\draw (-2,-2) .. controls (0,0) .. (2,-2);
\draw (-2,2) .. controls (-1,0) and (1,0) .. (2,2);
\end{tikzpicture}
\end{figure}
%------------------------------------------------------------------------------
%------------------------------------------------------------------------------
%Circles and arcs
\begin{figure}[p]
\begin{tikzpicture}
\filldraw[color=red!60, fill=red!5, very thick](-1,0) circle (1.5);
\fill[blue!50] (2.5,0) ellipse (1.5 and 0.5);
\draw[ultra thick, ->] (6.5,0) arc (0:220:1);
\end{tikzpicture}
\end{figure}
%------------------------------------------------------------------------------
%------------------------------------------------------------------------------
%Polygons
\begin{figure}[p]
\begin{tikzpicture}
\draw[blue, very thick] (0,0) rectangle (3,2);
\draw[orange, ultra thick] (4,0) -- (6,0) -- (5.7,2) -- cycle;
\end{tikzpicture}
\end{figure}
%------------------------------------------------------------------------------
%------------------------------------------------------------------------------
%Diagram
\begin{figure}
\begin{tikzpicture}[
roundnode/.style={circle, draw=green!60, fill=green!5, very thick, minimum size=7mm},
squarednode/.style={rectangle, draw=red!60, fill=red!5, very thick, minimum size=5mm},
]
%Nodes
\node[squarednode] (maintopic) {2};
\node[roundnode] (uppercircle) [above=of maintopic] {1};
\node[squarednode] (rightsquare) [right=of maintopic] {3};
\node[roundnode] (lowercircle) [below=of maintopic] {4};
%Lines
\draw[->] (uppercircle.south) -- (maintopic.north);
\draw[->] (maintopic.east) -- (rightsquare.west);
\draw[->] (rightsquare.south) .. controls +(down:7mm) and +(right:7mm) .. (lowercircle.east);
\end{tikzpicture}
\end{figure}
%------------------------------------------------------------------------------
%------------------------------------------------------------------------------
%List of available colors
\begin{figure}[p]
\begin{tikzpicture}
\filldraw[black] (0,0) rectangle (2,2);
\filldraw[red] (3,0) rectangle (5,2);
\filldraw[green] (6,0) rectangle (8,2);
\filldraw[blue] (9,0) rectangle (11,2);
\filldraw[cyan] (1,-1) rectangle (3,-3);
\filldraw[magenta] (4,-1) rectangle (6,-3);
\filldraw[yellow] (7,-1) rectangle (9,-3);
\end{tikzpicture}
\end{figure}
%------------------------------------------------------------------------------
%------------------------------------------------------------------------------
%Different levels of thickness
\begin{figure}[p]
\begin{tikzpicture}
\draw[blue, ultra thin] (-1,2) -- (1,-2);
\draw[blue, very thin] (0,2) -- (2,-2);
\draw[blue, thin] (1,2) -- (3,-2);
\draw[blue, thick] (2,2) -- (4,-2);
\draw[blue, very thick] (3,2) -- (5,-2);
\draw[blue, ultra thick] (4,2) -- (6,-2);
\end{tikzpicture}
\end{figure}
%------------------------------------------------------------------------------
\end{document}
答案1
不幸的是,我的tkz-graph
软件包目前已“过时”。它需要更新
\documentclass{standalone}
\usepackage{tkz-graph}
\begin{document}
\begin{tikzpicture}
\GraphInit[vstyle=Dijkstra]
\SetGraphUnit{4}
\Vertices{square}{G,D,A,F}
\WE(F){H}
\EA(A){B}
\EA(D){C}
\NO(A){E}
\Edge[label=$1$](H)(F)
\Edge[label=$4$](G)(F)
\Edge[label=$2$](H)(G)
\Edge[label=$2$](G)(D)
\Edge[label=$3$](D)(C)
\Edge[label=$4$](F)(E)
\Edge[label=$3$](A)(D)
\Edge[label=$2$](A)(E)
\Edge[label=$1$](A)(B)
\Edge[label=$2$](A)(C)
\Edge[label=$2$](C)(B)
\Edge[label=$3$](E)(B)
\SetUpEdge[lw=4pt,color=red]
\Edges[style={opacity=.2}](H,F,E,B)
\end{tikzpicture}
\end{document}
答案2
我无法告诉你绘制这种图表的最有效方法是什么,但下面可能是一种相当有效的方法。节点的位置由距离决定,请参阅这里。(绘图中有一个距离不一致。)更重要的是,您可以使用它overlay-beamer-styles
来使某些元素仅在某些覆盖层上可见。
\documentclass{beamer}
\usepackage{tikz}
\usetikzlibrary{arrows.meta, automata, calc,bending,positioning, quotes,
overlay-beamer-styles}
\tikzset{gl/.style={green!60!black,draw,bend left=20,-{Stealth[bend]},visible on=<#1>},
gr/.style={green!60!black,draw,bend right=20,-{Stealth[bend]},visible on=<#1>},
shortcut/.code={\def\pv##1{\pgfkeysvalueof{/tikz/#1/##1}}},
third corner of triangle/.style={shortcut=triangle pars,
triangle pars/.cd,#1,
/tikz/insert path={
let \p1=($(\pv{A})-(\pv{B})$),\n1={sqrt(pow(\x1/1cm,2)+pow(\y1/1cm,2))},
\n2={atan2(\y1,\x1)} in
(intersection cs:first line={(\pv{A})--($(\pv{A})+({\n2-cosinelaw(\n1,\pv{b},\pv{a})}:1)$)},
second line={(\pv{B})--($(\pv{B})+({\n2+cosinelaw(\n1,\pv{a},\pv{b})}:1)$)})
}},
declare function={cosinelaw(\a,\b,\c)=acos((\a*\a+\b*\b-\c*\c)/(2*\a*\b));},
triangle pars/.cd,
A/.initial=A,B/.initial=B,a/.initial=2,b/.initial=2}
\begin{document}
\begin{frame}[t]
\frametitle{An animated diagram}
\begin{tikzpicture}[
node distance = 22mm and 24mm,
every state/.append style = {inner sep=0pt, fill=gray!10,
minimum size=7mm},
every edge/.style = {draw}, auto=right]
\path[scale=0.3]
node[state,label={[visible on=<2->]below left:a},
alt=<3-5>{fill=yellow}{},
alt=<6->{fill=red}{}](1){1}
++ (-15:7) node[state,label={[blue,visible on=<3->]below:7},
alt=<7->{fill=red}{}](2){2}
edge["7"] (1)
[third corner of triangle={A=2,B=1,a=9,b=10}]
node[state,label={[blue,visible on=<4->]above:9},alt=<8->{fill=red}{}
] (3){3}
edge["9"] (1)
edge["10"] (2)
[third corner of triangle={A=2,B=3,a=11,b=15}]
node[state,alt=<8->{fill=red}{}] (4){4}
edge["15"] (2)
edge["11"] (3)
[third corner of triangle={A=3,B=1,a=14,b=7}]
node[state,label={[blue,visible on=<5->]above:14}] (6){6}
edge["14"] (1)
edge["7"] (3)
[third corner of triangle={A=4,B=6,a=9,b=6}]
node[state,label={[visible on=<-2>]above right:b}
] (5){5}
edge["6"] (4)
edge["9"] (6)
(1) edge[gr=3-] (2)
(2) edge[gr=4-] (3);
\end{tikzpicture}
\end{frame}
\end{document}
当然,这并不是试图完全重现您链接的动画,但它为您提供了实现这一目标的工具。请注意,您也可以使用standaloneframe
附带的\documentclass[beamer]{standalone}
。
附录:根据距离构建图表的方法,例如这个帖子。它利用了三角形在给定边长的情况下是唯一的(取决于符号选择)。因此,给定两个点和另外两个边的长度,您就可以确定第三个点(取决于符号)。
\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{automata, calc,quotes}
\begin{document}
\begin{tikzpicture}[
every state/.append style = {inner sep=0pt, fill=gray!10,
minimum size=7mm},
every edge/.style = {draw}, auto=right,
shortcut/.code={\def\pv##1{\pgfkeysvalueof{/tikz/#1/##1}}},
third corner of triangle/.style={shortcut=triangle pars,
triangle pars/.cd,#1,
/tikz/insert path={
let \p1=($(\pv{A})-(\pv{B})$),\n1={sqrt(pow(\x1/1cm,2)+pow(\y1/1cm,2))},
\n2={atan2(\y1,\x1)} in
(intersection cs:first line={(\pv{A})--($(\pv{A})+({\n2-cosinelaw(\n1,\pv{b},\pv{a})}:1)$)},
second line={(\pv{B})--($(\pv{B})+({\n2+cosinelaw(\n1,\pv{a},\pv{b})}:1)$)})
}},
declare function={cosinelaw(\a,\b,\c)=acos((\a*\a+\b*\b-\c*\c)/(2*\a*\b));},
triangle pars/.cd,
A/.initial=A,B/.initial=B,a/.initial=2,b/.initial=2]
\path[scale=0.3]
node[state,label={below left:a}](1){1}
++ (-15:7) node[state,label={[blue]below:7}](2){2}
edge["7"] (1)
[third corner of triangle={A=2,B=1,a=9,b=10}]
node[state,label={[blue]above:9}] (3){3}
edge["9"] (1)
edge["10"] (2)
[third corner of triangle={A=2,B=3,a=11,b=15}]
node[state] (4){4}
edge["15"] (2)
edge["11"] (3)
[third corner of triangle={A=3,B=1,a=14,b=7}]
node[state,label={[blue]above:14}] (6){6}
edge["14"] (1)
edge["7"] (3)
[third corner of triangle={A=4,B=6,a=9,b=6}]
node[state,label={above right:b}] (5){5}
edge["6"] (4)
edge["9"] (6);
\end{tikzpicture}
\end{document}
答案3
我喜欢问题描述中的解决方案#2,只需删除动画部分并将其粘贴在此处以供参考:
\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
\tikzset{
vertex/.style={circle,opacity=.8,fill=black!25,minimum size=20pt,inner sep=0pt},
edge/.style={draw,thick,-,auto},
weight/.style={font=\small},
}
% \node[anchor=south west,inner sep=0,opacity=1] (M) at (0,0){\includegraphics{a.png}};
\begin{scope}
\tikzset{
% x={(M.south east)},y={(M.north west)},
x=283,y=222,
}
% \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}; }
%
\foreach \pos/\name/\label in {
(0.13,0.21)/1/0,
(0.46,0.09)/2/$\infty$,
(0.43,0.59)/3/$\infty$,
(0.93,0.63)/4/$\infty$,
(0.58,0.88)/5/$\infty$,
(0.18,0.8)/6/$\infty$} {
\node[vertex,label=\label] (\name) at \pos {$\name$};
}
%
\foreach \source/ \dest /\weight in {
1/2/7,
1/3/9,
1/6/14,
2/4/15,
2/3/10,
3/4/11,
3/6/2,
4/5/6,
5/6/9} {
\path[edge] (\source) -- node[weight] {$\weight$} (\dest);
}
\end{scope}
\end{tikzpicture}
\end{document}
您可以使用参考图片来获取准确的节点位置,删除注释行并将参考图片放在那里,然后您就可以获得准确的坐标来填充节点位置循环。然后在完成所有操作后,只需将其注释掉并使用图片宽度/高度作为 x / y 来获取最终图片。