Wie kombiniere ich ein Balkendiagramm und ein Liniendiagramm mit pgfplots/tikz?

Wie kombiniere ich ein Balkendiagramm und ein Liniendiagramm mit pgfplots/tikz?

Ich versuche, ein Balkendiagramm und ein Liniendiagramm in einer Abbildung zu kombinieren. Ich habe die Masse von 5 verschiedenen Materialien für 3 verschiedene Dicken aufgetragen. Jetzt habe ich auch Temperaturdaten für alle 15 Balken. Für jedes Material möchte ich die drei Temperaturdatenpunkte in einer Linie verbinden, vorzugsweise mit Steigung. Wie verbinde ich jeden Temperaturwert mit dem jeweiligen Balken?

Das ist, was ich bisher habe. (Für Material 3 und 4 habe ich nur einen Temperaturwert, also ist die Option „Nur Markierungen“ in Ordnung.)

Balken- und Liniendiagramm

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

Antwort1

Sie erhalten die vertikalen Linien, da es bei Nichtverwendung zu ybarkeiner Koordinatenverschiebung kommt. Der Trick besteht also darin, sie auch ybarin der zweiten axisUmgebung zu verwenden. Da Sie sie aber nicht sehen/anzeigen möchten, machen wir sie unsichtbar und speichern die Koordinaten einfach, indem wir die nodes near coordsFunktion missbrauchen. Wenn sie vorhanden sind, ist es dann einfach, die Linien bzw. Markierungen zu zeichnen.

Einzelheiten entnehmen Sie bitte den Kommentaren im Code.
(Bitte beachten Sie, dass ich mir erlaubt habe, Ihren Code stark zu vereinfachen. Ich hoffe, Sie stimmen zu, dass dies viel lesbarer und damit wartbarer ist.)

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

Bild, das das Ergebnis des obigen Codes zeigt

Antwort2

Ich musste einige Werte Ihrer Einstellungen zurücksetzen, um eine halbwegs vernünftige Ausgabe und keine Warnungen zu erhalten. Eine Möglichkeit, Zugriff auf die vertikalen Positionen der Balken zu erhalten, ist die Verwendung nodes near coordsder automatischen Benennung vondiese AntwortDadurch ist eine Rekonstruktion der Handlungen möglich.

\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

Bildbeschreibung hier eingeben

Dies ist ein Machbarkeitsnachweis. Ich habe die überlappenden Balken nicht wirklich behoben, da ich wirklich keine Ahnung habe, welches Ergebnis Sie erzielen möchten. Wenn Sie dies jedoch in Ihrem Code beheben, kann diese Lösung verwendet werden. Ich behaupte definitiv nicht, dass dies die eleganteste Lösung ist, die möglich ist.

verwandte Informationen