Mehrfarbige und mit mehreren Balken gruppierte Diagramme

Mehrfarbige und mit mehreren Balken gruppierte Diagramme

Ich habe ein Python-Skript, das automatisch LaTeX-Codes zum Zeichnen von Balkendiagrammen generiert. Ein Beispiel für den generierten Code sieht so aus:

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

Es entstand dieses Diagramm:Aktuelle Handlung

Ich möchte jedoch, dass die beiden Echtzeitbalken übereinander gestapelt werden. Genau wie die CPU-Zeiten. So dass es zwei Balken pro X-Koordinate gibt. Der Python-Code, der diesen Latex-Code generiert hat, lautet:

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')

Die verarbeiteten Daten haben folgende Struktur:

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

Gibt es eine Möglichkeit, dies zu erreichen? Ich konnte die ganze Zeit nur mit einem Balken stapeln.

Aktualisieren:Ich möchte, dass die Echtzeitdaten gestapelt werden (Laden unten, Abfragen oben). Dasselbe gilt für die CPU-Zeit, wie in dieser Skizze gezeigt.

Skizze des gewünschten Grundstücks

Antwort1

Es scheint ein ziemlicher Aufwand zu sein, zwei gestapelte Balkendiagramme nebeneinander zu platzieren. Siehe z. B.diese Lösung von Jakeoderdas von Tom Bombadil.

Wenn Sie also nicht diesen Aufwand und diese Zeit für die Fehlerbehebung aufwenden möchten, schlage ich vor, einfach zwei Diagramme aus derselben Datenquelle zu zeichnen.Für Interessierte: Diese Konzeptänderung folgt den Mustern der erfinderischen Prinzipien: Mach ein bisschen weniger, mach zumindest eine Kopie.

Einige Bemerkungen.

Datendatei

Ich gehe von einer Datenstruktur wie dieser aus:

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

Hier sind die Daten einfach in der .tex-Datei enthalten, während Sie einfach data3.datetc in Ihrem Verzeichnis haben und dieses laden können, siehe unten.

Ich gehe davon aus, dass die ersten beiden Spalten zusammengehören, genau wie die beiden letzten. Wenn das falsch ist, ändern Sie einfach die y=Zuordnungen unten.

\addplot-s

Zeichnen Sie spaltenweise, z. B. hier die zweite Spalte mit dem Namen lrt. Ersetzen Sie die Dateinamen durch Ihre. Sagen Sie dem Programm, dass die Daten einen Header enthalten.

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

Achse

Nur zur Demonstration: Wenn Ihr Titel ein Komma enthält, setzen Sie alles innerhalb von { }. Die beiden Balkenanweisungen sind erforderlich. Setzen Sie sinnvolle Beschriftungen. Die Legendeneinträge sind nur Platzhalter: Verwenden Sie bessere Namen.

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

Vorgeschlagene Verbesserungen im Voraus

  • Verschieben Sie den Namen Ihrer Datendatei in ein \newcommand, ersetzen Sie das \addplots, um ihn nur an einer Stelle zu ändern
  • Ändern Sie die Farbschemata für beide Diagramme (siehe Handbuch).
  • Verschieben der Legende, z. B. nach außen (siehe Handbuch)
  • Breite und Höhe der Diagramme nach Bedarf anpassen
  • füge sie in eine articleKlasse oder Ähnliches ein, wenn das für dich in Ordnung ist; die Standalone-Version erstellt nur 2 Bilder (siehe Handbuch)
  • Handbücher finden Sie bei ctan, z. B. über Suchbegriffe in Ihrer Suchmaschinectan pgfplots
  • Stellen Sie sicher, dass sich Ihre Zeitintervalle nicht ändern, um eine falsche Visualisierung der Daten zu vermeiden

Ergebnis

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

Antwort2

MS-SPO-Antwortwies mich darauf hinJakes Lösungdas zur Generierung dieses Latex-Codes verwendet wurde:

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

Der Code hat dieses Diagramm erstellt:

Die Grafik

Es wurde dynamisch generiert durchPython-Funktion.

verwandte Informationen