如何在 LaTeX 中绘制列线图?

如何在 LaTeX 中绘制列线图?

什么是列线图

“A列线图,也称为诺模图、比对图或阿巴克图,是一种图形计算设备,是一种二维图表,旨在对函数进行近似的图形计算。”

例子

这张诺模图顶部给出的火箭方程式可以通过从左侧刻度到右侧刻度画一条线来求解。可以从中间的刻度读出解。

火箭方程的诺模图

问题

如何在 LaTeX 中重现上图?有没有 TikZ 方法?

附加问题

如何使用 LaTeX 创建任意列线图?

附加信息

上图的绘制使用了以下工具:http://pynomo.org/wiki/index.php?title=Main_Page

有关诺模分析的更多信息:http://www.slideshare.net/arulalan/nomography

答案1

免责声明

以此为起点:要使解决方案在所有情况下都能真正发挥作用,需要做一些事情。即:

  • 处理余数(最大值/最小值)!= 0 的情况
  • 处理最小值!=0
  • 处理从最大到最小的尺度以及从最小到最大的尺度

一个潜在可能:

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


\makeatletter
\newif\ifroundedenabled%
\newif\ifscalemaxtomin%
\newif\ifscalefromzero%
\pgfkeys{/nomogram/.cd,
  % keys for a single diagram
  part 1/.style={},
  part 2/.style={},
  part 3/.style={},
  single diagram/.cd,
  scale max to min/.is if=scalemaxtomin,
  scale max to min=false,
  scale from zero/.is if=scalefromzero,
  scale from zero=true,
  at pos/.store in=\dgrposition,
  at pos={(0,0)},
  height/.store in=\dgrheight,
  height=10cm,
  min value/.store in=\minval,
  min value=0,
  max value/.store in=\maxval,
  max value=10,
  step/.store in=\incstep,
  step=1,
  horizontal rule width/.store in=\horulewidth,
  horizontal rule width=1cm,
  min step/.store in=\minstep,
  min step={\incstep/2},
  minor tick rule width/.store in=\minortickrulewidth,
  minor tick rule width=3mm,
  little tick rule width/.store in=\litteltickrulewidth,
  little tick rule width=1mm,
  tick direction/.store in=\tickpos,
  tick direction=left,
  label above/.store in=\lababove,
  label above={},
  label sloped/.store in=\labsloped,
  label sloped={},
  label above rotation/.store in=\rotation,
  label above rotation=0,
  diagram/.code={
    \path \dgrposition node(A){};
    \pgfgetlastxy{\xA}{\yA};
    \ifscalemaxtomin%
      \pgfmathsetmacro\sndval{\maxval-\incstep}
      \foreach \y[count=\yi from 0] in {\maxval,\sndval,...,\minval}{
        \global\let\maxitems\yi%
      }%
    \else%
      \pgfmathsetmacro\sndval{\minval+\incstep}
      \foreach \y[count=\yi from 0] in {\minval,\sndval,...,\maxval}{
        \global\let\maxitems\yi%
      }%
    \fi  
    \draw(\xA,\yA)--++(0,\dgrheight)
     node[pos=0.5,sloped,above]{\labsloped}
     node[above,rotate=\rotation,transform shape]{\lababove};% vertical line+above label
    \pgfmathsetmacro\actualstep{\dgrheight/\maxitems}%
        % little ticks
        \pgfmathsetmacro\littletickstep{\actualstep/10}
    \foreach \y in {0,\littletickstep,...,\dgrheight}{
     \ifnum\pdf@strcmp{\tickpos}{left}=\z@%
       \draw(\xA,\yA+\y pt) --++(-\litteltickrulewidth,0);
     \fi%
     \ifnum\pdf@strcmp{\tickpos}{right}=\z@%
        \draw(\xA,\yA+\y pt) --++(\litteltickrulewidth,0);
     \fi%
    }%
    % min step
    \pgfmathsetmacro\mintickstep{\actualstep/2}
    \ifscalemaxtomin%
      \foreach \y [count=\yi from 0,
             evaluate=\yi as \ytext using ((\maxval-\yi*\incstep+\yi*\incstep/2))]
              in {0,\mintickstep,...,\dgrheight}{%
        \ifnumodd{\yi}{% true
        \ifnum\pdf@strcmp{\tickpos}{left}=\z@%  
          \draw (\xA,\yA+\y pt) --++(-\minortickrulewidth,0) 
            node[left,font=\footnotesize]{\pgfmathprintnumber{\ytext}};
        \fi%
        \ifnum\pdf@strcmp{\tickpos}{right}=\z@%
          \draw (\xA,\yA+\y pt) --++(\minortickrulewidth,0) 
            node[right,font=\footnotesize]{\pgfmathprintnumber{\ytext}};
        \fi%
        }{}%
      }%
    \else%
      \foreach \y [count=\yi from 0,
         evaluate=\yi as \ytext using ((\yi*\incstep+2*\minval)/2)] in 
         {0,\mintickstep,...,\dgrheight}{%
        \ifnumodd{\yi}{% true
          \ifnum\pdf@strcmp{\tickpos}{left}=\z@%  
            \draw (\xA,\yA+\y pt) --++(-\minortickrulewidth,0) 
              node[left,font=\footnotesize]{\pgfmathprintnumber{\ytext}};
          \fi%
         \ifnum\pdf@strcmp{\tickpos}{right}=\z@%
            \draw (\xA,\yA+\y pt) --++(\minortickrulewidth,0) 
              node[right,font=\footnotesize]{\pgfmathprintnumber{\ytext}};
         \fi%
        }{}%
      }%
    \fi%  
    % main step
    \ifscalemaxtomin%
      \ifscalefromzero%
          \foreach \y[count=\yi from 0,
              evaluate=\yi as \ytext using (\maxval-\yi*\incstep)] in 
              {0,\actualstep,...,\dgrheight}{%
            \ifnum\pdf@strcmp{\tickpos}{left}=\z@%  
              \pgfkeys{/pgf/number format/.cd,fixed,precision=2}
              \draw (\xA,\yA+\y pt) --++(-\horulewidth,0) 
                node[left]{\pgfmathprintnumber{\ytext}};
            \fi%
            \ifnum\pdf@strcmp{\tickpos}{right}=\z@%
              \pgfkeys{/pgf/number format/.cd,fixed,precision=2}
              \draw (\xA,\yA+\y pt) --++(\horulewidth,0) 
                node[right]{\pgfmathprintnumber{\ytext}};
            \fi%
              }%
      \else%
          \foreach \y[count=\yi from 0,
              evaluate=\yi as \ytext using (\maxval-\yi*\incstep)] in 
              {0,\actualstep,...,\dgrheight}{%
            \ifnum\pdf@strcmp{\tickpos}{left}=\z@%  
              \pgfkeys{/pgf/number format/.cd,fixed,precision=2}
              \draw (\xA,\yA+\y pt) --++(-\horulewidth,0) 
                node[left]{\pgfmathprintnumber{\ytext}};
            \fi%
            \ifnum\pdf@strcmp{\tickpos}{right}=\z@%
              \pgfkeys{/pgf/number format/.cd,fixed,precision=2}
              \draw (\xA,\yA+\y pt) --++(\horulewidth,0) 
                node[right]{\pgfmathprintnumber{\ytext}};
            \fi%
              }%
          \fi%
    \else%
      \ifscalefromzero%
          \foreach \y[count=\yi from 0,
              evaluate=\yi as \ytext using (\yi*\sndval+\minval)] in 
              {0,\actualstep,...,\dgrheight}{%
            \ifnum\pdf@strcmp{\tickpos}{left}=\z@%  
              \pgfkeys{/pgf/number format/.cd,fixed,precision=2}
              \draw (\xA,\yA+\y pt) --++(-\horulewidth,0) 
                node[left]{\pgfmathprintnumber{\ytext}};
            \fi%
            \ifnum\pdf@strcmp{\tickpos}{right}=\z@%
              \pgfkeys{/pgf/number format/.cd,fixed,precision=2}
              \draw (\xA,\yA+\y pt) --++(\horulewidth,0) 
                node[right]{\pgfmathprintnumber{\ytext}};
            \fi%        
              }%
      \else%
          \foreach \y[count=\yi from 0,
              evaluate=\yi as \ytext using (\yi*\incstep+\minval)] in 
              {0,\actualstep,...,\dgrheight}{%
            \ifnum\pdf@strcmp{\tickpos}{left}=\z@%  
              \pgfkeys{/pgf/number format/.cd,fixed,precision=2}
              \draw (\xA,\yA+\y pt) --++(-\horulewidth,0) 
                node[left]{\pgfmathprintnumber{\ytext}};
            \fi%
            \ifnum\pdf@strcmp{\tickpos}{right}=\z@%
              \pgfkeys{/pgf/number format/.cd,fixed,precision=2}
              \draw (\xA,\yA+\y pt) --++(\horulewidth,0) 
                node[right]{\pgfmathprintnumber{\ytext}};
            \fi%        
              }%
          \fi%
    \fi%
  }%
}

% that's just an alias for \node
\def\drawnomogrampart{\tikz@path@overlay{node}}
\makeatother

\begin{document}

\begin{tikzpicture}
\drawnomogrampart[/nomogram/single diagram/.cd,
height=7cm,
min value=50,
max value=130,
step=10,
label above=$\Delta v$,
scale from zero=false,
diagram]{};
\begin{scope}[rotate=-30,transform shape]
\drawnomogrampart[/nomogram/single diagram/.cd,
horizontal rule width=0.5cm,
height=8cm,
min value=0,
max value=0.901,% for rounding purposes
step=0.1,
label above rotation=30,
label above={$M_f=1-\textrm{e}^{-\Delta v/9.81*I_{sp}}$},
label sloped={Mass Fraction $(M_f)$},
tick direction=right,
diagram]{};
\end{scope}
\drawnomogrampart[/nomogram/single diagram/.cd,
scale from zero=false,
height=7cm,
scale max to min=true,
min value=400,
max value=2000,
step=200,
at pos={(7,0)},
tick direction=right,
label above=IPS (s),
diagram]{};
\end{tikzpicture}
\end{document}

结果:

在此处输入图片描述

答案2

由于使用 进行计算存在精度问题TikZ,我改变了方法,并使用一个小脚pearl本来进行计算。运行pdflatex -shell-script

我使用decorations.markings库对每种类型的路径进行分级。(不再有标记累积问题)。

我尝试在代码中添加一些解释。

在此处输入图片描述

在此处输入图片描述

代码 :

\documentclass[tikz,margin=2pt]{standalone}
\usetikzlibrary{calc}
\usetikzlibrary{decorations.markings,intersections}


    %%%%                        ---- Use path several times
    %%%%                        ---- thanks to Andrew Stacey
    \makeatletter
    \tikzset{
      use path for main/.code={%
        \tikz@addmode{%
          \expandafter\pgfsyssoftpath@setcurrentpath\csname tikz@intersect@path@name@#1\endcsname
        }%
      },
      use path for actions/.code={%
        \expandafter\def\expandafter\tikz@preactions\expandafter{\tikz@preactions\expandafter\let\expandafter\tikz@actions@path\csname tikz@intersect@path@name@#1\endcsname}%
      },
      use path/.style={%
        use path for main=#1,
        use path for actions=#1,
      }
    }

\pgfkeys{/MonoG/.cd,
    % foot of the scale
    path/.store in=\p@th,
    path={(0,0)--(0,10)},
    % minimale value
    min/.store in=\Min,
    min=0,
    % maximale value 
    max/.store in=\Max,
    max=10,
    % Major graduation Step
    step/.store in=\Step,
    step=1,
    % Big ticks
    % tick length
    big ticks/.store in=\BTick,
    big ticks=.7,
    % font (whatever compatible with tikz font parameter)
    big ticks font/.store in=\BFont,
    big ticks font=\small,
    % line width
    big ticks width/.store in=\BWidth,
    big ticks width=thick,
    % medium ticks (same choices)
    med ticks/.store in=\MTick,
    med ticks=.4,
    med ticks font/.store in=\MFont,
    med ticks font=\footnotesize,
    med ticks width/.store in=\MWidth,
    med ticks width=thin,
    % small ticks
    small ticks/.store in=\STick,
    small ticks=.2,
    small ticks width/.store in=\SWidth,
    small ticks width=very thin,
    % number of sublevel of small tick
    small ticks level/.store in=\STlevel,
    small ticks level=1,
    % tick direction
    tick direction/.store in=\TickPos,
    tick direction=right,
    % bottom label
    bottom label/.store in=\BotLabel,
    bottom label={},
    % midway label
    midway label/.store in=\MidLabel,
    midway label={},
    % top label
    top label/.store in=\TopLabel,
    top label={},
    % Reverse graduation    
    reverse/.store in=\Reverse,
    reverse=false,
    diagram/.code={%

    % draw the path and place the nodes for labelling
    \draw[\BWidth,name path=Path] \p@th 
        node[pos=1,above] (MnAbove) {\TopLabel}
        node[midway,sloped,above] (MnMid) {\MidLabel}
        node[pos=0,below] (MnBelow) {\BotLabel} ;

    % left right position flag
    \ifnum\pdf@strcmp{\TickPos}{left}=\z@%
        \def\TPos{1}
    \fi%
    \ifnum\pdf@strcmp{\TickPos}{right}=\z@%
        \def\TPos{-1}
    \fi%

    % reverse scale flag    
    \def\Rev{1}
    \ifnum\pdf@strcmp{\Reverse}{true}=\z@%
        \def\Rev{-1}
    \fi%

% set the style for the tick labels
\tikzset{Big/.style={font=\BFont,\TickPos,transform shape,rotate=-90},
    Med/.style={font=\MFont,\TickPos,transform shape,rotate=-90},
    /pgf/decoration/reset marks % Reset marks each time
        % to avoid accumulation problems
    } ;

% Call of external calculation script
    \immediate\write18{%
    ./script.pl     \Min\space%
        \Max\space%
        \Step\space%
        \STlevel\space\STick\space > Sortie.tex}

    \input{Sortie}
    }
}
\makeatother



\begin{document}

\begin{tikzpicture}
\path[/MonoG/.cd,
    step=5,
    min=5,
    max=25.01,
    path={(4,0) parabola (8,10)},
    diagram
    ] ;

\path[/MonoG/.cd,
    step=1000,
    max=4500,
    tick direction=left,
    small ticks=.2,     
    small ticks level=2,
    top label=$\Delta_V$,
    diagram
    ] ;

% to avoid 5.10e-2
\pgfkeys{/pgf/number format/.cd,fixed,precision=3}

\path[/MonoG/.cd,
    path={(11,0)--(11,10)},
    step=100,
    max=800,
    min=199.9,
    reverse=true,
    small ticks level=2,
    small ticks = .3,
    top label=IPS (s),
    diagram
    ] ;

\path[/MonoG/.cd,
    step=.1,
    max=.9,
    path={(0,0)--(4,10)},
    midway label=Mass Fraction $(M_f)$,
    top label={$M_f=1-\textrm{e}^{-\Delta v/9.81*I_{sp}}$},
    diagram
    ] ;

\end{tikzpicture}
    \begin{tikzpicture}
    \path[/MonoG/.cd,
        step=10,
        max=12,
        small ticks level=2,
        diagram
        ] ;

    \path[/MonoG/.cd,
        step=1,
        max=10.01,
        min=0,
        tick direction=left,  
        diagram
        ] ;


    \path[/MonoG/.cd,
        path={(3,0)--(3,10)},
        min=.2,
        step=5,
        max=9.7,
        diagram
        ] ;

    \path[/MonoG/.cd,
        tick direction=left,
        path={(3,0)--(3,10)},
        min=-5,
        step=5,
        max=15,
        diagram
        ] ;

    \path[/MonoG/.cd,
        path={(12,0) arc (0:180:3)},
        min=0,
        step=30,
        small ticks level=2,        
        max=180.01,
        diagram
        ] ;
    \end{tikzpicture}

\end{document}

剧本pearl

#!/usr/bin/perl -w

use POSIX "fmod" ;

$Min = $ARGV[0] ;       # Minimum
$Max = $ARGV[1] ;       # Maximum
$Step = $ARGV[2] ;      # Step of graduation
$Level =  $ARGV[3] ;    # level of small ticks default 1
$TickL =  $ARGV[4] ;    # length of small ticks (1st level)

$Coeff = $Max-$Min ;  # Scale on the path from 0 to 1 

$Begin = $Min - fmod($Min,$Step) ;  # Calculation of the place  
if ( $Begin < $Min ) {              # of the first Label
    $Begin += $Step ; }

$X = $Begin ;
$Y =  ($X - $Min) / $Coeff ;

print "\\begin{scope}[decoration={markings," ;
while ($X <= $Max) {    
    print "mark=at position $Y*\\Rev with {\\draw[\\BWidth] (0,0) --++ (0,\\BTick*\\TPos) node[Big] {\\pgfmathprintnumber{$X}} ;},\n" ;
    $X += $Step ; 
    $Y = ($X - $Min) / $Coeff ; 
    }
print "}]\n" ;
print "\\draw[postaction={decorate},use path=Path];\n" ;
print "\\end{scope}\n" ;


## half step
$X = $Begin - $Step/2 ;             # Calculation of            
if ( $X < $Min ) { $X += $Step ; }  # the first Label
$Y = ($X - $Min) / $Coeff ;

print "\\begin{scope}[decoration={markings," ;
while ($X <= $Max) {    
    print "mark=at position $Y*\\Rev with {\\draw[\\MWidth] (0,0) --++ (0,\\MTick*\\TPos) node[Med] {\\pgfmathprintnumber{$X}} ;},\n" ;
    $X += $Step ; 
    $Y = ($X - $Min) / $Coeff ; 
    }
print "}]\n" ;
print "\\draw[postaction={decorate},use path=Path];\n" ;
print "\\end{scope}\n" ;


## 10e ...
$Step /= 10 ;

$Begin = $Min - fmod($Min,$Step) ;  # Calculation of            
if ( $Begin < $Min ) {              # the first Label
    $Begin += $Step ; }
if ( $Begin < $Min ) { $Begin += $Step ; }  # the first Label

for (my $i = 1; $i <= $Level ; $i++) {
    $X = $Begin ;
    $Y = ($X - $Min) / $Coeff ;
print "\\begin{scope}[decoration={markings," ;
    while ($X <= $Max) {    
        print "mark=at position $Y*\\Rev with {\\draw[very thin] (0,0) --++ (0,$TickL*\\TPos) ;},\n" ;      
        $X += $Step ; 
        $Y = ($X - $Min) / $Coeff ; 
        }
print "}]\n" ;
print "\\draw[postaction={decorate},use path=Path];\n" ;
print "\\end{scope}\n" ;
    $Step /= 2 ;
    $TickL /= 2 ;
    }

相关内容