如何让 Tikz 代码更加简洁?

如何让 Tikz 代码更加简洁?

我刚刚开始学习使用 PGFPlots 的 TikZ,并尝试了一个简单的热力学 pV 图示例。我对图像很满意,但我知道使用 foreach 循环等可以使代码更加简洁。任何帮助都将不胜感激!

很多原始代码来自以前的 StackExchange 答案作者:Stefan Pinnow。

\documentclass[border=5pt]{standalone}
\usepackage{pgfplots}
    \usetikzlibrary{
        decorations.markings,
    }
\tikzset{
    fleche/.style args={#1:#2}{
        postaction=decorate,
        decoration={
            name=markings,
            mark=at position #1 with {\arrow[#2,scale=2]{>}}
        },
    },
}

\pgfplotsset{
    /pgf/declare function={
        % define V1, V2 and P1
        Vone = 3;
        Vtwo = 6;
        Pone = 6;
        % calculate constant nRT
        nRT = Vone * Pone;
        % now any P can be calculated for a given V
        P(\V) = nRT/\V;
        % for simplicity of later use already calc P2 here and assign the
        % result to a constant
        Ptwo = P(Vtwo);
    },
}

\pgfplotsset{
    /pgf/declare function={
        V1one = 3;
        V1two = 6;
        P1one = 4.56;
        nRT1 = V1one * P1one;
        P1(\V) = nRT1/\V;
        P1two = P1(V1two);
    },
}

\pgfplotsset{
    /pgf/declare function={
        V2one = 3;
        V2two = 6;
        P2one = 3;
        nRT2 = V2one * P2one;
        P2(\V) = nRT2/\V;
        P2two = P2(V2two);
    },
}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
axis x line=bottom,
axis y line=left,
xmin=0,xmax=10,
ymin=0,ymax=10,
ticks = none,
xlabel = Volume,
ylabel = Pressure,
]

\draw [thick, fleche = {0.6:black}] (9/7, 7) -- (18/7,7) node [right = 0.3 cm, fill = white] {Isobaric};
\draw [thick, fleche = {0.6:black}] (18/7,7) -- (18/7,7/2) node [below = 0.5 cm, fill = white] {Isochoric};
\draw [thick, fleche = {0.6:black}] (V1one, P1one) .. controls (4,2.6) .. (V2two, P2two) node[below = 0.2cm, fill = white] {Adiabatic};

\draw[fill = black] (V1one, P1one) circle (2pt);
\draw[fill = black] (V2two, P2two) circle (2pt);
\draw[fill = black] (Vone, Pone) circle (2pt);
\draw[fill = black] (Vtwo, Ptwo) circle (2pt);
\draw[fill = black] (9/7, 7) circle (2pt);
\draw[fill = black] (18/7, 7) circle (2pt);
\draw[fill = black] (18/7, 7/2) circle (2pt);

% Isothermal a bit different
addplot [
thick,
domain=Vone:Vtwo,
fleche={0.6:black},
] {P(x)} node [above = 0.4cm] {Isothermal}
;

\addplot [
thin,
domain=1:8,
] {P(x)};

\addplot [
thin,
domain=1:8,
] {P1(x)};

\addplot [
thin,
domain=1:8,
] {P2(x)};

\end{axis}
\end{tikzpicture}
\end{document}

在此处输入图片描述

答案1

总体来说,这对我来说看起来还不错。以下是您可以采取的措施,以避免重复并改善外观。

  • 不需要添加几个形式的语句\draw[fill = black] (V1one, P1one) circle (2pt);,只需添加即可\addplot[only marks,mark=*] coordinates{ <list of coordinates>};
  • 不要使用三个几乎相同的图\pgfplotsinvokeforeach{P,P1,P2}{\addplot [thin,domain=1:8,] {#1(x)};}
  • 而不是fleche使用能产生弯箭的东西。

\documentclass[tikz,border=3mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.17} 
\usetikzlibrary{arrows.meta,bending,decorations.markings}
\tikzset{% 
    ->-/.style={
    decoration={
        markings,
         mark=at position 0 with {\pgfextra{%
         \pgfmathsetmacro{\tmpArrowTime}{\pgfkeysvalueof{/tikz/arc arrow/length}/(\pgfdecoratedpathlength)}%
         \xdef\tmpArrowTime{\tmpArrowTime}}},
        mark=at position {#1-3*\tmpArrowTime} with {\coordinate(@1);},
        mark=at position {#1-2*\tmpArrowTime} with {\coordinate(@2);},
        mark=at position {#1-1*\tmpArrowTime} with {\coordinate(@3);},
        mark=at position {#1+\tmpArrowTime/2} with {\coordinate(@4);
        \draw[-{Stealth[length=\pgfkeysvalueof{/tikz/arc arrow/length},bend]}] plot[smooth]
         coordinates {(@1) (@2) (@3) (@4)};},
        },
     postaction=decorate,
     },
     ->-/.default=0.5,
     arc arrow/.cd,length/.initial=2.5mm,
}
\pgfplotsset{
    /pgf/declare function={
        % define V1, V2 and P1
        Vone = 3;
        Vtwo = 6;
        Pone = 6;
        % calculate constant nRT
        nRT = Vone * Pone;
        % now any P can be calculated for a given V
        P(\V) = nRT/\V;
        % for simplicity of later use already calc P2 here and assign the
        % result to a constant
        Ptwo = P(Vtwo);
    },
}

\pgfplotsset{
    /pgf/declare function={
        V1one = 3;
        V1two = 6;
        P1one = 4.56;
        nRT1 = V1one * P1one;
        P1(\V) = nRT1/\V;
        P1two = P1(V1two);
    },
}

\pgfplotsset{
    /pgf/declare function={
        V2one = 3;
        V2two = 6;
        P2one = 3;
        nRT2 = V2one * P2one;
        P2(\V) = nRT2/\V;
        P2two = P2(V2two);
    },
}

\begin{document}

\begin{tikzpicture}
\begin{axis}[
axis x line=bottom,
axis y line=left,
xmin=0,xmax=10,
ymin=0,ymax=10,
ticks = none,
xlabel = Volume,
ylabel = Pressure,
]

\draw [thick, ->-] (9/7, 7) -- (18/7,7) node [right = 0.3 cm, fill = white] {Isobaric};
\draw [thick, ->-] (18/7,7)  -- (18/7,7/2) node [below = 0.5 cm, fill = white] {Isochoric};
\draw [thick, ->-] (V1one, P1one) .. controls (4,2.6) .. (V2two, P2two) node[below = 0.2cm, fill = white] {Adiabatic};

\addplot[only marks,mark=*] coordinates{
     (V1one, P1one) 
     (V2two, P2two) 
     (Vone, Pone) 
     (Vtwo, Ptwo) 
     (9/7, 7) 
     (18/7, 7) 
     (18/7, 7/2) };

% Isothermal a bit different
\addplot [
thick,
domain=Vone:Vtwo,
->-,
] {P(x)} node [above = 0.4cm] {Isothermal}
;
\pgfplotsinvokeforeach{P,P1,P2}{%
\addplot [
thin,
domain=1:8,
] {#1(x)};}

\end{axis}
\end{tikzpicture}

\end{document}

在此处输入图片描述

相关内容