Gráficos agrupados multicoloridos e com várias barras

Gráficos agrupados multicoloridos e com várias barras

Eu tenho um script Python que gera automaticamente códigos LaTeX que traçam gráficos de barras. Um exemplo do código gerado é semelhante a:

\documentclass[border=10pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{width=7cm,compat=1.8}
\usepackage{pgfplotstable}
\renewcommand*{\familydefault}{\sfdefault}
\usepackage{sfmath}
\begin{document}
\begin{tikzpicture}
  \centering
  \begin{axis}[
        ybar, axis on top,
        title={Performance charts},
        height=8cm, width=15.5cm,
        bar width=1.5cm,
        ymajorgrids, tick align=inside,
        major grid style={draw=white},
        enlarge y limits={value=.1,upper},
        ymin=0, ymax=0.01,
        axis x line*=bottom,
        axis y line*=right,
        y axis line style={opacity=0},
        tickwidth=0pt,
        enlarge x limits=true,
        legend style={
            at={(0.5,-0.2)},
            anchor=north,
            legend columns=-1,
            /tikz/every even column/.append style={column sep=0.5cm}
        },
        ylabel={Time (seconds)},
        symbolic x coords={
           10,
           20,
       },
       xtick=data,
       nodes near coords={
        \pgfmathprintnumber[precision=3]{\pgfplotspointmeta}
       }
    ]
    \addplot+[ybar, fill=blue!50] plot coordinates {
      (10, 0.001223850250244141)
      (20, 0.001497483253479004)
    };
    \addplot+[ybar, fill=blue!25] plot coordinates {
      (10, 0.00045402050018310557)
      (20, 0.001987481117248536)
    };
    \addplot+[ybar, fill=red!50] plot coordinates {
      (10, 0.0008006999999999999)
      (20, 0.0010588)
    };
    \addplot+[ybar, fill=red!25] plot coordinates {
      (10, 0.0002661999999999997)
      (20, 0.0012075)
    };
    \legend{Real Time (Loading), Real-Time (Querying), CPU Time (Loading), CPU Time (Querying)}
  \end{axis}
\end{tikzpicture}
\end{document}

Ele produziu este gráfico:Gráfico atual

No entanto, quero que as duas barras em tempo real sejam empilhadas uma sobre a outra. O mesmo que os tempos de CPU. Para que haja duas barras por coordenada x. O código Python que gerou este código látex é:

def generate_latex_files(data, env_name, output_dir: Path) -> None:
    for key, values in data.items():
        if key[0] == env_name:
            # Sort values by graph size
            values.sort(key=lambda x: x[0])

            # Calculate maximum value for ymax
            max_value = max(sum(val['loading'] + val['querying']) for _, val in values) * 1.1

            file_name = f'{key[1]}_{key[2]}.tex'
            full_file_name = output_dir / env_name / file_name
            full_file_name.parent.mkdir(exist_ok=True, parents=True)
            with open(full_file_name, 'w') as f:
                f.write('\\documentclass[border=10pt]{standalone}\n')
                f.write('\\usepackage{pgfplots}\n')
                f.write('\\pgfplotsset{width=7cm,compat=1.8}\n')
                f.write('\\usepackage{pgfplotstable}\n')
                f.write('\\renewcommand*{\\familydefault}{\\sfdefault}\n')
                f.write('\\usepackage{sfmath}\n')
                f.write('\\begin{document}\n')
                f.write('\\begin{tikzpicture}\n')
                f.write('  \\centering\n')
                f.write('  \\begin{axis}[\n')
                f.write('        ybar, axis on top,\n')
                f.write(f'        title={{Performance charts}},\n')
                f.write('        height=8cm, width=15.5cm,\n')
                f.write('        bar width=1.5cm,\n')
                f.write('        ymajorgrids, tick align=inside,\n')
                f.write('        major grid style={draw=white},\n')
                f.write('        enlarge y limits={value=.1,upper},\n')
                f.write(f'        ymin=0, ymax={max_value:.2f},\n')
                f.write('        axis x line*=bottom,\n')
                f.write('        axis y line*=right,\n')
                f.write('        y axis line style={opacity=0},\n')
                f.write('        tickwidth=0pt,\n')
                f.write('        enlarge x limits=true,\n')
                f.write('        legend style={\n')
                f.write('            at={(0.5,-0.2)},\n')
                f.write('            anchor=north,\n')
                f.write('            legend columns=-1,\n')
                f.write('            /tikz/every even column/.append style={column sep=0.5cm}\n')
                f.write('        },\n')
                f.write('        ylabel={Time (seconds)},\n')
                f.write('        symbolic x coords={\n')
                for value in values:
                    f.write(f'           {value[0]},\n')
                f.write('       },\n')
                f.write('       xtick=data,\n')
                f.write('       nodes near coords={\n')
                f.write('        \\pgfmathprintnumber[precision=3]{\\pgfplotspointmeta}\n')
                f.write('       }\n')
                f.write('    ]\n')

                # Real time plots
                f.write('    \\addplot+[ybar, fill=blue!50] plot coordinates {\n')
                for value in values:
                    f.write(f'      ({value[0]}, {value[1]["loading"][0]})\n')
                f.write('    };\n')
                f.write('    \\addplot+[ybar, fill=blue!25] plot coordinates {\n')
                for value in values:
                    f.write(f'      ({value[0]}, {value[1]["querying"][0]})\n')
                f.write('    };\n')

                # CPU time plots
                f.write('    \\addplot+[ybar, fill=red!50] plot coordinates {\n')
                for value in values:
                    f.write(f'      ({value[0]}, {value[1]["loading"][1]})\n')
                f.write('    };\n')
                f.write('    \\addplot+[ybar, fill=red!25] plot coordinates {\n')
                for value in values:
                    f.write(f'      ({value[0]}, {value[1]["querying"][1]})\n')
                f.write('    };\n')

                f.write('    \\legend{Real-Time (Loading), Real-Time (Querying), CPU Time (Loading), CPU Time (Querying)}\n')
                f.write('  \\end{axis}\n')
                f.write('\\end{tikzpicture}\n')
                f.write('\\end{document}\n')

Os dados que estão sendo processados ​​possuem esta estrutura:

{
   (<env_name>, <graph_type>, <mode>): [(<graph_size>, {'loading': (<real_time>, <cpu_time>), 'querying': (<real_time>, <cpu_time>)}),...]
}

Existe uma maneira de conseguir isso? Só consegui empilhar todas as vezes com uma barra.

Atualizar:Quero que os dados em tempo real sejam empilhados (carregando na parte inferior, consultando na parte superior). O mesmo se aplica ao tempo de CPU mostrado neste esboço.

Esboço do enredo desejado

Responder1

Parece ser um esforço colocar dois gráficos de barras empilhados lado a lado. Veja, por exemploesta solução de Jakeouisso de Tom Bombadil.

Portanto, a menos que você queira despender esse esforço e tempo para depuração, sugiro simplesmente desenhar dois diagramas da mesma fonte de dados.Para os interessados, esta mudança de conceito segue os padrões dos Princípios Inventivos: faça um pouco menos, faça uma cópia, pelo menos.

Algumas observações.

Arquivo de dados

Presumo uma estrutura de dados como esta:

 \begin{filecontents}{data2.dat}
 time  lrt lct  qrt qct
 10     5   4   3   3
 20     7   5   4   3
 30     4   7   5   2
 \end{filecontents}

Aqui os dados são incluídos apenas no arquivo .tex, enquanto você pode ter apenas data3.datetc em seu diretório e carregá-lo, veja abaixo.

Presumo que as duas primeiras colunas estejam juntas, assim como as duas últimas. Se estiver errado, basta alterar as y=atribuições abaixo.

\addplot-s

Plote coluna por coluna, por exemplo, aqui a segunda chamada lrt. substitua o(s) nome(s) do(s) arquivo(s) pelo(s) seu(s). Diga ao programa que os dados contêm um cabeçalho.

    \addplot table[header=true,x=time,y=lrt]{data2.dat};% i.e. your data file

eixo

Apenas para demonstração, se o seu título contiver vírgula, coloque tudo dentro de { }. As duas instruções da barra são necessárias. Coloque rótulos úteis. As entradas da legenda são apenas simulações: use nomes melhores.

   \begin{axis}[
        title={Real-time data, Load},   
        ybar stacked,
        stack plots=y,
        xmin=0, xmax=50,
        xlabel=time (s),
        ylabel=percent,
        legend entries={lrt, lct},% replace by better names
    ]

Refinamentos sugeridos adiante

  • mova o nome do seu arquivo de dados para um \newcommand, substitua no \addplots, para alterá-lo em apenas um lugar
  • altere os esquemas de cores para ambos os gráficos (consulte o manual)
  • mova a legenda, por exemplo, para fora (veja o manual)
  • ajuste a largura e a altura dos diagramas de acordo com suas necessidades
  • coloque-os em uma articleclasse ou similar, se for conveniente para você; autônomo apenas cria 2 imagens (veja seu manual)
  • encontre manuais no ctan, por exemplo, por meio de termos de pesquisa em seu mecanismo de pesquisactan pgfplots
  • certifique-se de que seus intervalos de tempo não mudem, para evitar visualização errada dos dados

resultado

\documentclass[10pt,border=3mm,tikz]{standalone}
\usepackage{pgfplots}

\begin{document}
 % ~~~ pretending you have said file in your directory
 %     assuming lrt= load real timeetc.
 %     assuming, this is your data structure

 \begin{filecontents}{data2.dat}
 time  lrt lct  qrt qct
 10     5   4   3   3
 20     7   5   4   3
 30     4   7   5   2
 \end{filecontents}

 % ~~~ Concept: Draw two diagrams
 \begin{tikzpicture}    % LOAD
   \begin{axis}[
        title={Real-time data, Load},   
        ybar stacked,
        stack plots=y,
        xmin=0, xmax=50,
        xlabel=time (s),
        ylabel=percent,
        legend entries={lrt, lct},% replace by better names
    ]
    \addplot table[header=true,x=time,y=lrt]{data2.dat};% i.e. your data file
    \addplot table[header=true,x=time,y=lct]{data2.dat};    
   \end{axis}
 \end{tikzpicture}
 
 % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 \begin{tikzpicture}    % CPU
   \begin{axis}[
        title={Real-time data, CPU},    
        ybar stacked,
        stack plots=y,
        xmin=0, xmax=50,
        xlabel=time (s),
        ylabel=percent,
        legend entries={qrt,qct},
    ]
    \addplot table[header=true,x=time,y=qrt]{data2.dat};
    \addplot table[header=true,x=time,y=qct]{data2.dat};
    
   \end{axis}
 \end{tikzpicture}

\end{document}

Responder2

Resposta MS-SPOme indicouA solução de Jakeque foi usado para gerar este código de látex:

\documentclass[border=10pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}
\makeatletter
\newcommand\resetstackedplots{
   \pgfplots@stacked@isfirstplottrue
   \addplot [forget plot,draw=none] coordinates{(10,0) (20,0)};
}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
   ybar stacked,
   title={Performance charts},
   height=0.019\textheight, width=1.5\textwidth,
   bar width=0.8cm,
   ymajorgrids, tick align=inside,
   major grid style={draw=gray!20},
   xtick=data,
   ymin=0,
   axis x line*=bottom,
   axis y line*=left,
   enlarge x limits=0.4,
   legend entries={
       Real Time (Loading),
       Real Time (Querying),
       CPU Time (Loading),
       CPU Time (Querying),
   },
   legend style={
       at={(0.5,-0.2)},
       anchor=north,
       legend columns=-1,
   },
   ylabel={Time (seconds)},
   xlabel={Graph Size},
   symbolic x coords={
           10,
           20,
       },
]
\addplot +[bar shift=-.5cm] coordinates {
    (10, 0.001223850250244141)
    (20, 0.001497483253479004)
};
\addplot +[bar shift=-.5cm] coordinates {
    (10, 0.00045402050018310557)
    (20, 0.001987481117248536)
};
\resetstackedplots
\addplot +[bar shift=.5cm] coordinates {
    (10, 0.0008006999999999999)
    (20, 0.0010588)
};
\addplot +[bar shift=.5cm] coordinates {
    (10, 0.0002661999999999997)
    (20, 0.0012075)
};
\end{axis}
\end{tikzpicture}
\end{document}

O código produziu este gráfico:

O gráfico

Foi gerado dinamicamente por esteFunção Python.

informação relacionada