¿Cómo combino un gráfico de barras y un gráfico de líneas con pgfplots/tikz?

¿Cómo combino un gráfico de barras y un gráfico de líneas con pgfplots/tikz?

Estoy intentando combinar un gráfico de barras y un gráfico de líneas en una sola figura. Tracé la masa de 5 materiales diferentes para 3 espesores diferentes. Ahora también tengo datos de temperatura para las 15 barras. Para cada material, quiero conectar los tres puntos de datos de temperatura en una línea, preferiblemente inclinada. ¿Cómo conecto cada valor de temperatura a la barra respectiva?

Esto es lo que obtuve hasta ahora. (Para los materiales 3 y 4, solo tengo un valor de temperatura, por lo que la opción "solo marcas" está bien).

gráfico de barras y líneas

\documentclass{article}
\usepackage{pgfplots}
\usepackage{anysize}
\pgfplotsset{compat=1.16}

\begin{document}   
\begin{figure}[!ht]
\centering
\pgfplotsset{width=14.5cm,
symbolic x coords={material1,material2,material3,material4,material5},
}
\begin{tikzpicture}
\begin{axis}
[
ybar=11pt,
axis x line*=bottom,
axis y line*=left,
ymin=0,ymax=1500,  
ylabel=material mass $\mathrm{[kg]}$, 
enlarge y limits=0.0,
enlarge x limits=0.15,
legend style={at={(1,-0.1)},draw=none}, 
legend columns=3,
x tick label style={text width=2.9cm,align=center},
xtick={data},
xtick align=inside,
minor y tick num=1,
height=0.37\linewidth,
bar width=0.5cm,
]
\addplot
[fill=black!30,draw=none] 
coordinates{
    (material1, 316.91)
    (material2,338.93)
    (material3,542.05)
    (material4,653.4)
    (material5,244.72)
};
\addplot
[fill=black!60,draw=none] 
coordinates{
    (material1,475.05)
    (material2,508.06)
    (material3,812.13 )
    (material4,979.44)
    (material5,366.83 )
};
\addplot
[fill=black!80,draw=none] 
coordinates{
    (material1,623.97)
    (material2,676.96)
    (material3,1084.65)
    (material4,1305.05)
    (material5,488.78)
};
\end{axis}
\begin{axis}
[
ymin=0,ymax=600,
axis y line*=right,
ylabel=temperature $\mathrm{[K]}$, 
enlarge y limits=0.0, 
enlarge x limits=0.15, 
height=0.37\linewidth,
xticklabels=\empty
]
\addplot[very thick,draw=red!90]
coordinates{
    (material1, 387.04)
    (material1,274.51)
    (material1,211.07)
};
\addplot[mark=circle,very thick,draw=red!90]
coordinates{
    (material2,461.93)
    (material2,326.88)
    (material2,253.97)
};
\addplot[only marks,very thick,draw=red!90]
coordinates{
    (material3,530.84)};
\addplot[only marks,very thick,draw=red!90]
coordinates{
    (material4,484.68)};
\addplot[mark=circle,very thick,draw=red!90]
coordinates{
    (material5,515.55)
    (material5,350.43)
    (material5,268.02)
};
\end{axis}
\end{tikzpicture}
\end{figure}
\end{document}

Respuesta1

Obtienes las líneas verticales, porque cuando no las usas ybarno hay cambio de coordenadas. Entonces el truco consiste en usarlo también ybaren el segundo axisentorno. Pero como no desea verlos ni mostrarlos, los hacemos invisibles y simplemente almacenamos las coordenadas haciendo un mal uso de la nodes near coordsfunción. Al tenerlos es sencillo dibujar las líneas y marcas, respectivamente.

Para obtener más información, eche un vistazo a los comentarios en el código.
(Tenga en cuenta que me permití simplificar enormemente su código. Espero que esté de acuerdo en que es mucho más legible y, por lo tanto, más fácil de mantener).

% used PGFPlots v1.16
\documentclass[border=5pt]{standalone}
\usepackage{pgfplotstable}
    \pgfplotsset{
        compat=1.16,
        % create a custom style to store common `axis options`
        my axis style/.style={
            width=\linewidth,
            height=0.37\linewidth,
            ybar=5pt,       % <-- reduced so the bars don't overlap
            bar width=0.5cm,
            enlarge y limits=0.0,
            enlarge x limits=0.15,
            % to avoid to repeat the symbolic coords over and over again,
            % use them from a table ...
            xticklabels from table={\data}{material},
            % ... ensure that every data points get a corresponding xtick ...
            xtick={data},
            % ... and then just number the entries by the row index of the table
            table/x expr={\coordindex},
            xtick align=inside,
            minor y tick num=1,
        },
        % create a style to store the coordinates of the
        % temperature data
        Name/.style={
            % use the `nodes near coords` for that
            nodes near coords,
            nodes near coords style={
                % they shouldn't show any value ...
                coordinate,
                % but store coordinate labels which can later be used
                name=#1\coordindex,
            },
        },
    }
    % create a table of data
    % (which is much more clearly arranged than the "coordinates")
    % use any number that can clearly be distinguished from regular values to indicate
    % that you don't have any data here. In this case, I used -1.
    % (You can't use NaN here, because then no coordinate will be created and thus
    %  the (automatic) numbering of the named coordinates is working as expected.)
    \pgfplotstableread{
        material    d1      d2      d3      T1      T2      T3
        material1   316.91  475.05  623.97  387.04  274.51  211.07
        material2   338.93  508.06  676.96  461.93  326.88  253.97
        material3   542.05  812.13  1084.65 -1      530.84  -1
        material4   653.40  979.44  1305.05 -1      484.68  -1
        material5   244.72  366.83  488.78  515.55  350.43  268.02
    }{\data}
\begin{document}
\begin{tikzpicture}
    \begin{axis}[
        % call the created style
        my axis style,
        % (list the remaining options)
        ymin=0,
        ymax=1500,
        axis x line*=bottom,
        axis y line*=left,
        ylabel=material mass $\mathrm{[kg]}$,
        % use a (custom) `cycle list` which is also much clearer than
        % providing the options to each `\addplot` command
        cycle list={
            {draw=none,fill=black!30},
            {draw=none,fill=black!60},
            {draw=none,fill=black!80},
        },
    ]
        % then this here is very simple
        % (and should be self-explanatory)
        \addplot table [y=d1] {\data};
        \addplot table [y=d2] {\data};
        \addplot table [y=d3] {\data};
    \end{axis}

    % here we also create a ybar plot, but don't draw the bars.
    % Instead, we just store named coordinates at the bar ends.
    \begin{axis}[
        my axis style,
        %
        ymin=0,
        ymax=600,
        axis y line*=right,
        ylabel=temperature $\mathrm{[K]}$,
        xticklabels=\empty,
        % make the bars invisible
        only marks,
    ]
        % use the custom `Name` style here to store the named coordinates
        \addplot [Name=a] table [y=T1] {\data};
        \addplot [Name=b] table [y=T2] {\data};
        \addplot [Name=c] table [y=T3] {\data};
    \end{axis}

    % the named coordinates can only be accessed after the `axis` environment.
    % Now simply draw the lines ...
    \foreach \i in {0,1,4} {
        \draw [very thick,red!90] (a\i) -- (b\i) -- (c\i);
    }

    % ... and marks
    \foreach \i in {2,3} {
        \fill [red!90] (b\i) circle [radius=2.5pt];
    }

\end{tikzpicture}
\end{document}

imagen que muestra el resultado del código anterior

Respuesta2

Tuve que restablecer algunos valores de su configuración para obtener un resultado semi-razonable y sin advertencias. Una posible forma de acceder a las posiciones verticales de las barras es utilizar nodes near coordsel auto-nombramiento deesta respuesta. Esto permite reconstruir las tramas.

\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.16}

\begin{document}   
\begin{figure}[!ht]
\centering
\pgfplotsset{width=0.8\linewidth,
symbolic x coords={material1,material2,material3,material4,material5},
}
\pgfplotsset{% https://tex.stackexchange.com/a/75811/121799
    name nodes near coords/.style={nodes near coords={},
        every node near coord/.append style={anchor=center,coordinate,
            name=#1-\coordindex,%/utils/exec=\typeout{#1-\coordindex},
            alias=#1-last,
        },
    },
    name nodes near coords/.default=coordnode
}

\begin{tikzpicture}
\begin{axis}
[
ybar=11pt,
axis x line*=bottom,
axis y line*=left,
ymin=0,ymax=1500,  
ylabel=material mass $\mathrm{[kg]}$, 
enlarge y limits=0.0,
enlarge x limits=0.15,
legend style={at={(1,-0.1)},draw=none}, 
legend columns=3,
x tick label style={text width=2.9cm,align=center},
xtick={data},
xtick align=inside,
minor y tick num=1,
height=0.37\linewidth,
bar width=0.3cm,
]
\addplot
[fill=black!30,draw=none,name nodes near coords=m1] 
coordinates{
    (material1, 316.91)
    (material2,338.93)
    (material3,542.05)
    (material4,653.4)
    (material5,244.72)
};
\addplot
[fill=black!60,draw=none,name nodes near coords=m2] 
coordinates{
    (material1,475.05)
    (material2,508.06)
    (material3,812.13 )
    (material4,979.44)
    (material5,366.83 )
};
\addplot
[fill=black!80,draw=none,name nodes near coords=m3] 
coordinates{
    (material1,623.97)
    (material2,676.96)
    (material3,1084.65)
    (material4,1305.05)
    (material5,488.78)
};
\end{axis}
\begin{axis}
[
ymin=0,ymax=600,
axis y line*=right,
ylabel=temperature $\mathrm{[K]}$, 
enlarge y limits=0.0, 
enlarge x limits=0.15, 
height=0.37\linewidth,
xticklabels=\empty
]
\addplot[very thick,draw=red!90,opacity=0,name nodes near coords=n1]
coordinates{
    (material1, 387.04)
    (material1,274.51)
    (material1,211.07)
};
\addplot[mark=circle,very thick,draw=red!90,opacity=0,name nodes near coords=n2]
coordinates{
    (material2,461.93)
    (material2,326.88)
    (material2,253.97)
};
\addplot[only marks,very thick,draw=red!90]
coordinates{
    (material3,530.84)};
\addplot[only marks,very thick,draw=red!90]
coordinates{
    (material4,484.68)};
\addplot[mark=circle,very thick,draw=red!90,opacity=0,name nodes near coords=n5]
coordinates{
    (material5,515.55)
    (material5,350.43)
    (material5,268.02)
};
\end{axis}
\draw[very thick,draw=red!90] plot[samples at={0,1,2}] 
(m\the\numexpr\x+1\relax-0|-n1-\x);
\draw[mark=*,very thick,draw=red!90]
     plot[samples at={0,1,2}] (m\the\numexpr\x+1\relax-1|-n2-\x);
\draw[mark=*,very thick,draw=red!90]
     plot[samples at={0,1,2}] (m\the\numexpr\x+1\relax-4|-n5-\x);
\end{tikzpicture}
\end{figure}
\end{document}2

ingrese la descripción de la imagen aquí

Ésta es una prueba de principio. Realmente no arreglé las barras superpuestas porque realmente no tengo idea de qué resultado buscas. Sin embargo, si soluciona esto en su código, se puede utilizar esta solución. Definitivamente no estoy diciendo que esta sea la solución más elegante posible.

información relacionada