简单甘特图

简单甘特图

甘特图 latex 功能真的很复杂。我只想要一个像这样的简单小东西,用于可视化调度算法

在此处输入图片描述

我该怎么做?


预计到达时间:我代码来自这里并添加颜色。

\definecolor{p1}{HTML}{5780dc}
\definecolor{p2}{HTML}{dc0404}
\definecolor{p3}{HTML}{1ec81e}
\definecolor{p4}{HTML}{8424ac}
\definecolor{p5}{HTML}{e68142}

\begin{tikzpicture}[
    node distance = 0pt,
    G/.style = {draw, color=white, text width=2*#1mm, align=center,
                inner xsep=0pt, outer sep=0pt, 
                anchor=south west},
    tck/.style = {font=\scriptsize, below}
]
\newlength{\prev}
\foreach \n/\i [remember=\i as \j (initially 0), 
                evaluate=\i as \k using \i-\j] in {
                    1/2, 2/3, 3/11, 4/15, 5/20
                }
{
\node[G=\k, fill=p\n] at (\j/5,0) {$P_\n$};
    \node[tck] at (\i/5,0) {\i};
\ifnum\j=0
    \node[tck] at (0,0) {\j};
\fi
}
\end{tikzpicture}

总体来说还不错,但如果宽度只有 1,怎么办?太窄了,文本会被截断。

在此处输入图片描述

我该如何改变它以避免这种情况?我想让整个东西变宽,而不是让文本变小。

另外,有没有办法有一个 sum 变量?每次都可以将数字添加到某个变量中,以便变量是前面数字的总和?这样输入就可以是:

{p2/2, p1/1, p4/4, p5/5, p3/8}

答案1

这是关于一个可自定义的简单甘特图的建议(不过可能有点过头了)。您可以定义一组要循环的颜色,自定义刻度的宽度和高度以及位置,还可以设置一个阈值来决定标签是放在节点内还是作为图钉。当前的一个缺点是颜色的定义无法限定范围。

\documentclass[border=10pt]{standalone}
\usepackage{tikz}

\newif\ifsimplegantttickpositionbelow
\tikzset{
    pics/simple gantt/.style={
        code={
            \ifsimplegantttickpositionbelow
                \path[/tikz/simple gantt/tick] (0,0) -- 
                    ++(0,{-1*\pgfkeysvalueof{/tikz/simple gantt/tick length}}) 
                    node[/tikz/simple gantt/tick label] {\pgfmathprintnumber{0}};
            \else
                \path[/tikz/simple gantt/tick] (0,\pgfkeysvalueof{/tikz/simple gantt/height}) -- 
                    ++(0,{\pgfkeysvalueof{/tikz/simple gantt/tick length}}) 
                    node[/tikz/simple gantt/tick label] {\pgfmathprintnumber{0}};
            \fi
            \foreach \n/\x [count=\i, remember=\x as \lastx (initially 0)] in {#1} {
                \ifsimplegantttickpositionbelow
                    \path[/tikz/simple gantt/tick] ({\x*\pgfkeysvalueof{/tikz/simple gantt/width unit}},0) -- 
                        ++(0,{-1*\pgfkeysvalueof{/tikz/simple gantt/tick length}}) 
                        node[/tikz/simple gantt/tick label] {\pgfmathprintnumber{\x}};
                \else
                    \path[/tikz/simple gantt/tick] ({\x*\pgfkeysvalueof{/tikz/simple gantt/width unit}},\pgfkeysvalueof{/tikz/simple gantt/height}) -- 
                        ++(0,{\pgfkeysvalueof{/tikz/simple gantt/tick length}}) 
                        node[/tikz/simple gantt/tick label] {\pgfmathprintnumber{\x}};
                \fi
                \pgfmathparse{int(mod(\i - 1, \pgfkeysvalueof{/tikz/simple gantt/color cycle length}) + 1)} 
                \global\pgfkeyslet{/tikz/simple gantt/color cycle step}{\pgfmathresult}
                \path[
                    /tikz/simple gantt/box, 
                    fill={simple gantt color \pgfkeysvalueof{/tikz/simple gantt/color cycle step}},
                ]
                    ({\lastx*\pgfkeysvalueof{/tikz/simple gantt/width unit}},0) rectangle 
                    ({\x*\pgfkeysvalueof{/tikz/simple gantt/width unit}},\pgfkeysvalueof{/tikz/simple gantt/height})
                    \pgfextra{\pgfmathparse{\x - \lastx}}
                    \ifdim\pgfmathresult pt < \pgfkeysvalueof{/tikz/simple gantt/label as pin if value below} pt\relax
                        node[/tikz/simple gantt/label, pin={[/tikz/simple gantt/label pin]\pgfkeysvalueof{/tikz/simple gantt/label pin angle}:\n}] {}
                    \else
                        node[/tikz/simple gantt/label] {\n}
                    \fi ;
            }
        }
    },
    simple gantt/color cycle length/.initial={0},
    simple gantt/color cycle step/.initial={1},
    simple gantt/color cycle/.code={
        \foreach \c [count=\i] in {#1} {
            \xglobal\colorlet{simple gantt color \i}{\c}
            \global\pgfkeyslet{/tikz/simple gantt/color cycle length}{\i}
        }
    },
    simple gantt/height/.initial={1cm},
    simple gantt/width unit/.initial={1cm},
    simple gantt/box/.style={},
    simple gantt/label/.style={pos=0.5},
    simple gantt/label pin/.style={above, pin edge={black, thin}, pin distance=0.5cm},
    simple gantt/label pin angle/.initial={90},
    simple gantt/label as pin if value below/.initial={1.5},
    simple gantt/tick/.style={draw},
    simple gantt/tick label/.style={below},
    simple gantt/tick position/.is choice,
    simple gantt/tick position/above/.code={\simplegantttickpositionbelowfalse},
    simple gantt/tick position/below/.code={\simplegantttickpositionbelowtrue},
    simple gantt/tick position={below},
    simple gantt/tick length/.initial={5pt},
    simple gantt/color cycle={blue!50, red!50, green!50},
}

\begin{document}

\begin{tikzpicture}

    \tikzset{
        simple gantt/.cd,
        width unit=0.33cm,
        box/.style={draw},
    }

    \pic at (0,0) {simple gantt={$P_1$/2, $P_2$/3, $P_3$/11, $P_4$/15, $P_5$/20}};

    \tikzset{
        simple gantt/.cd,
        height=0.75cm,
        color cycle={yellow, orange, cyan, magenta},
        label pin angle={270},
        label pin/.append style={below},
        tick position={above},
        tick label/.append style={above},
        label as pin if value below={4},
    }

    \pic at (0,-3) {simple gantt={A/1, B/3, C/9, D/10, E/20, F/25}};
    
\end{tikzpicture}

\end{document}

在此处输入图片描述


使用类似 的方法可以更轻松地确定颜色范围color cycle/.list={}。但是,为了正确循环颜色,我需要此列表的长度,但我发现很难正确存储它。也许,使用 ID 先于其他列表定义颜色列表,然后pic使用 ID 为每个列表引用定义颜色列表会更容易。

无论如何,我找到了一种以某种方式确定颜色列表范围的方法,但我很确定这不是最简单、最直接的方法:

\documentclass[border=10pt]{standalone}
\usepackage{tikz}

\newif\ifsimplegantttickpositionbelow
\newcounter{simpleganttcolorindex}
\tikzset{
    pics/simple gantt/.style={
        /tikz/simple gantt/color cycle get length/.expanded={\pgfkeysvalueof{/tikz/simple gantt/color cycle list}},
        code={
            \ifsimplegantttickpositionbelow
                \path[/tikz/simple gantt/tick] (0,0) -- 
                    ++(0,{-1*\pgfkeysvalueof{/tikz/simple gantt/tick length}}) 
                    node[/tikz/simple gantt/tick label] {\pgfmathprintnumber{0}};
            \else
                \path[/tikz/simple gantt/tick] (0,\pgfkeysvalueof{/tikz/simple gantt/height}) -- 
                    ++(0,{\pgfkeysvalueof{/tikz/simple gantt/tick length}}) 
                    node[/tikz/simple gantt/tick label] {\pgfmathprintnumber{0}};
            \fi
            \foreach \n/\x [count=\i, remember=\x as \lastx (initially 0)] in {#1} {
                \ifsimplegantttickpositionbelow
                    \path[/tikz/simple gantt/tick] ({\x*\pgfkeysvalueof{/tikz/simple gantt/width unit}},0) -- 
                        ++(0,{-1*\pgfkeysvalueof{/tikz/simple gantt/tick length}}) 
                        node[/tikz/simple gantt/tick label] {\pgfmathprintnumber{\x}};
                \else
                    \path[/tikz/simple gantt/tick] ({\x*\pgfkeysvalueof{/tikz/simple gantt/width unit}},\pgfkeysvalueof{/tikz/simple gantt/height}) -- 
                        ++(0,{\pgfkeysvalueof{/tikz/simple gantt/tick length}}) 
                        node[/tikz/simple gantt/tick label] {\pgfmathprintnumber{\x}};
                \fi
                \pgfmathparse{int(mod(\i - 1, \pgfkeysvalueof{/tikz/simple gantt/color cycle length}) + 1)} 
                \pgfkeyslet{/tikz/simple gantt/color cycle step}{\pgfmathresult}
                \path[
                    /tikz/simple gantt/box, 
                    fill={simple gantt color \pgfkeysvalueof{/tikz/simple gantt/color cycle step}},
                ]
                    ({\lastx*\pgfkeysvalueof{/tikz/simple gantt/width unit}},0) rectangle 
                    ({\x*\pgfkeysvalueof{/tikz/simple gantt/width unit}},\pgfkeysvalueof{/tikz/simple gantt/height})
                    \pgfextra{\pgfmathparse{\x - \lastx}}
                    \ifdim\pgfmathresult pt < \pgfkeysvalueof{/tikz/simple gantt/label as pin if value below} pt\relax
                        node[/tikz/simple gantt/label, pin={[/tikz/simple gantt/label pin]\pgfkeysvalueof{/tikz/simple gantt/label pin angle}:\n}] {}
                    \else
                        node[/tikz/simple gantt/label] {\n}
                    \fi ;
            }
        }
    },
    simple gantt/.cd,
    color cycle step/.initial={1},
    color cycle list/.initial={},
    color cycle length/.initial={1},
    color cycle loop/.code={
        \stepcounter{simpleganttcolorindex}
    },
    color cycle get length/.code={
        \setcounter{simpleganttcolorindex}{0}
        \pgfkeys{
            /tikz/simple gantt/color cycle loop/.list={#1},
            /tikz/simple gantt/color cycle length={\thesimpleganttcolorindex},
        }
    },
    color cycle define colors/.code={
        \stepcounter{simpleganttcolorindex}
        \colorlet{simple gantt color \thesimpleganttcolorindex}{#1}
    },
    color cycle/.code={
        \setcounter{simpleganttcolorindex}{0}
        \pgfkeys{
            /tikz/simple gantt/color cycle list={#1},
            /tikz/simple gantt/color cycle define colors/.list={#1},
        }
    },
    height/.initial={1cm},
    width unit/.initial={1cm},
    box/.style={},
    label/.style={pos=0.5},
    label pin/.style={above, pin edge={black, thin}, pin distance=0.5cm},
    label pin angle/.initial={90},
    label as pin if value below/.initial={1.5},
    tick/.style={draw},
    tick label/.style={below},
    tick position/.is choice,
    tick position/above/.code={\simplegantttickpositionbelowfalse},
    tick position/below/.code={\simplegantttickpositionbelowtrue},
    tick position={below},
    tick length/.initial={5pt},
    color cycle={blue!50, red!50, green!50},
}

\begin{document}

\begin{tikzpicture}

    \tikzset{
        simple gantt/.cd,
        width unit=0.33cm,
        box/.style={draw},
    }

    \pic at (0,0) {simple gantt={$P_1$/2, $P_2$/3, $P_3$/11, $P_4$/15, $P_5$/20}};

    \begin{scope}
    
    \tikzset{
        simple gantt/.cd,
        height=0.75cm,
        color cycle={yellow, orange, cyan, magenta},
        label pin angle={270},
        label pin/.append style={below},
        tick position={above},
        tick label/.append style={above},
        label as pin if value below={4},
    }

    \pic at (0,-3) {simple gantt={A/1, B/3, C/9, D/10, E/20, F/25}};

    \end{scope}
    
    \pic at (0,-6) {simple gantt={A/1, B/3, C/9, D/10, E/20, F/25}};

\end{tikzpicture}

\end{document}

在此处输入图片描述

答案2

我使用 Mathcha 完成的 MWE 与图像的原始颜色一起添加。

\documentclass[a4paper,12pt]{article}
\usepackage{tikz}


\begin{document}



\tikzset{every picture/.style={line width=0.75pt}} %set default line width to 0.75pt        

\begin{tikzpicture}[x=0.75pt,y=0.75pt,yscale=-1,xscale=1]
%uncomment if require: \path (0,467); %set diagram left start at 0, and has height of 467

%Shape: Rectangle [id:dp007554265052235776] 
\draw  [draw opacity=0][fill={rgb, 255:red, 87; green, 128; blue, 220 }  ,fill opacity=1 ] (131,123) -- (201,123) -- (201,163) -- (131,163) -- cycle ;
%Shape: Rectangle [id:dp431468506218484] 
\draw  [draw opacity=0][fill={rgb, 255:red, 220; green, 4; blue, 4 }  ,fill opacity=1 ] (201,123) -- (231.33,123) -- (231.33,163) -- (201,163) -- cycle ;
%Shape: Rectangle [id:dp2215419221563808] 
\draw  [draw opacity=0][fill={rgb, 255:red, 30; green, 200; blue, 30 }  ,fill opacity=1 ] (231.33,123) -- (351.33,123) -- (351.33,163) -- (231.33,163) -- cycle ;
%Shape: Rectangle [id:dp3305984746556416] 
\draw  [draw opacity=0][fill={rgb, 255:red, 132; green, 36; blue, 172 }  ,fill opacity=1 ] (351.33,123) -- (401.33,123) -- (401.33,163) -- (351.33,163) -- cycle ;
%Shape: Rectangle [id:dp2743597291571982] 
\draw  [draw opacity=0][fill={rgb, 255:red, 230; green, 129; blue, 66 }  ,fill opacity=1 ] (401.33,123) -- (490.33,123) -- (490.33,163) -- (401.33,163) -- cycle ;

% Text Node
\draw (127,164) node [anchor=north west][inner sep=0.75pt]   [align=left] {0};
% Text Node
\draw (194,164) node [anchor=north west][inner sep=0.75pt]   [align=left] {7};
% Text Node
\draw (225.33,164) node [anchor=north west][inner sep=0.75pt]   [align=left] {10};
% Text Node
\draw (341,164) node [anchor=north west][inner sep=0.75pt]   [align=left] {22};
% Text Node
\draw (393,164) node [anchor=north west][inner sep=0.75pt]   [align=left] {27};
% Text Node
\draw (477,164) node [anchor=north west][inner sep=0.75pt]   [align=left] {36\\};
% Text Node
\draw (149,137) node [anchor=north west][inner sep=0.75pt]   [align=left] {\textcolor[rgb]{1,1,1}{P1 \ \ \ \ \ \  P2 \ \ \ \ \ \ \ \ \ \ P3 \ \ \ \ \ \ \ \ \ \ \ P4 \ \ \ \ \ \ \ \ \ P5 \ \ \ }};
\end{tikzpicture}
\end{document}

在此处输入图片描述

答案3

我以 Sebastiano 的代码为基础,但对其进行了简化:

\begin{document}
\definecolor{p1}{HTML}{5780dc}
\definecolor{p2}{HTML}{dc0404}
\definecolor{p3}{HTML}{1ec81e}
\definecolor{p4}{HTML}{8424ac}
\definecolor{p5}{HTML}{e68142}

\begin{tikzpicture}
    \foreach \n/\i [remember=\i as \j (initially 0)] in {1/2, 2/3, 3/11, 4/15, 5/20}
    {
        \draw[fill=p\n] (\j/2,0) rectangle node{\textcolor[rgb]{1,1,1}{$P_\n$}} (\i/2,1);
        \draw (\i/2,-0.1) node [anchor=north][inner sep=0.75pt][align=center] {\i};
    }
    \draw (0,-0.1) node [anchor=north][inner sep=0.75pt][align=center] {0};
\end{tikzpicture}

\end{document}

这样可以最轻松地替换图表中的不同值。例如:

{1/2, 2/3, 3/11, 4/15, 5/20}

在此处输入图片描述

{1/2, 2/3, 3/5, 4/7, 5/9, 3/11, 4/13, 5/15, 3/17, 5/18, 3/20}

在此处输入图片描述

答案4

如果您想要一些简单的东西,您可以尝试{tabular}用彩色单元格绘制。

使用经典的{tabular}colortbl,绘制表格并控制单元格宽度会很容易。但是,放置标签会稍微复杂一些。使用{NiceTabular}nicematrix类似于经典的{tabular}),您可以将标签放在 Tikz 中所需的位置(在所谓的 中\CodeAfter)。

\documentclass{article}
\usepackage{nicematrix,tikz}

\begin{document}

\NiceMatrixOptions{cell-space-top-limit=1mm}

\begin{NiceTabular}{wc{1cm} c w{c}{10mm} w{c}{10mm} w{c}{2cm}}[colortbl-like]
\RowStyle[color=white]{\sffamily}
  \cellcolor{blue!70}    P1 &
  \cellcolor{red!70}     P2 &
  \cellcolor{green!70}   P3 &
  \cellcolor{blue!70}    P4 &
  \cellcolor{magenta!70} P5 
\CodeAfter
  \begin{tikzpicture} [below] \small 
   \node at (2-|1) { 0 } ; 
   \node at (2-|2) { 7 } ; 
   \node at (2-|3) { 10 } ; 
   \node at (2-|4) { 22 } ; 
   \node at (2-|5) { 27 } ; 
   \node at (2-|6) { 36 } ; 
  \end{tikzpicture}
\end{NiceTabular}

\end{document}

上述代码的输出

相关内容