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}
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.
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.dat
etc 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\addplot
s, 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
article
Klasse 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 Suchmaschine
ctan pgfplots
- Stellen Sie sicher, dass sich Ihre Zeitintervalle nicht ändern, um eine falsche Visualisierung der Daten zu vermeiden
\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:
Es wurde dynamisch generiert durchPython-Funktion.