막대 그래프와 선 차트를 pgfplots/tikz와 어떻게 결합합니까?

막대 그래프와 선 차트를 pgfplots/tikz와 어떻게 결합합니까?

막대 그래프와 선 차트를 하나의 그림으로 결합하려고 합니다. 나는 3가지 다른 두께에 대해 5가지 다른 재료의 질량을 플롯했습니다. 이제 15개 막대 모두에 대한 온도 데이터도 있습니다. 각 재료에 대해 세 개의 온도 데이터 지점을 경사진 한 선으로 연결하고 싶습니다. 각 온도 값을 해당 막대에 어떻게 연결합니까?

이것이 내가 지금까지 얻은 것입니다. (재료 3과 4의 경우 온도 값이 하나만 있으므로 "표시만" 옵션은 괜찮습니다.)

막대 및 선 차트

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

답변1

사용하지 않을 때 좌표 ybar이동이 없기 때문에 수직선이 나타납니다. 그래서 비결은 ybar두 번째 axis환경에서도 사용하는 것입니다. 하지만 보거나 보여주고 싶지 않기 때문에 보이지 않게 만들고 기능을 오용하여 좌표만 저장합니다 nodes near coords. 이를 사용하면 선과 표시를 각각 그리는 것이 간단합니다.

자세한 내용은 코드의 주석을 살펴보시기 바랍니다.
(저는 귀하의 코드를 크게 단순화하도록 허용했습니다. 이것이 훨씬 더 읽기 쉽고 유지 관리가 용이하다는 데 동의하시기 바랍니다.)

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

위 코드의 결과를 보여주는 이미지

답변2

어느 정도 합리적인 출력을 얻고 경고가 표시되지 않도록 설정의 몇 가지 값을 재설정해야 했습니다. 막대의 수직 위치에 접근할 수 있는 한 가지 방법은 nodes near coords다음에서 자동 이름 지정 기능을 사용하는 것입니다.이 답변. 이를 통해 플롯을 재구성할 수 있습니다.

\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

여기에 이미지 설명을 입력하세요

이것은 원칙의 증명입니다. 나는 당신이 어떤 결과를 얻었는지 전혀 모르기 때문에 겹치는 막대를 실제로 고치지 않았습니다. 그러나 코드에서 이 문제를 수정하면 이 솔루션을 사용할 수 있습니다. 나는 이것이 가능한 가장 우아한 해결책이라고 확실히 말하지 않습니다.

관련 정보