¿Cómo puedo dibujar nomogramas en LaTeX?

¿Cómo puedo dibujar nomogramas en LaTeX?

¿Qué es un nomograma?

"Anomograma, también llamado nomograma, gráfico de alineación o abaque, es un dispositivo de cálculo gráfico, un diagrama bidimensional diseñado para permitir el cálculo gráfico aproximado de una función”.

Ejemplo

La ecuación del cohete, que aparece en la parte superior de este nomograma, se puede resolver trazando una línea desde la escala de la izquierda hasta la escala de la derecha. La solución se puede leer en la escala situada en el centro.

Nomograma de la ecuación del cohete.

Pregunta

¿Cómo puedo reproducir la figura anterior en LaTeX? ¿Existe un enfoque TikZ?

Pregunta extra

¿Cómo puedo crear nomogramas arbitrarios con LaTeX?

información adicional

La figura anterior ha sido creada con:http://pynomo.org/wiki/index.php?title=Main_Page

Más sobre nomografía:http://www.slideshare.net/arulalan/nomography

Respuesta1

Descargo de responsabilidad

Tome esto como punto de partida: hay algunas cosas que hacer para que la solución realmente funcione en todos los casos. A saber:

  • manejar casos donde el resto (máx./mín.)!=0
  • manejar min!=0
  • manejar la escala de máximo a mínimo además de mínimo a máximo

Una posibilidad:

\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}

El resultado:

ingrese la descripción de la imagen aquí

Respuesta2

Debido a problemas de precisión con los cálculos TikZ, cambio el enfoque y uso un pequeño pearlscript para hacer estos cálculos. Corre conpdflatex -shell-script

Utilizo decorations.markingsla biblioteca para hacer graduaciones en todo tipo de camino. (No más problema de acumulaciones de marcas).

Intenté poner algunas explicaciones en el código.

ingrese la descripción de la imagen aquí

ingrese la descripción de la imagen aquí

El código :

\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}

La pearlsecuencia de comandos

#!/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 ;
    }

información relacionada