drei pgfplots nebeneinander mit gemeinsamer Legende darüber

Tabellen und Grafiken erstellen und anordnen


chris_Waechter

drei pgfplots nebeneinander mit gemeinsamer Legende darüber

Beitrag von chris_Waechter »

Hallo,

ich habe drei Diagramme mit je zwei Achsen mit pgfplots die ich gerne nebeneinander anzeigen lassen möchte. Der Graph zeigt jedesmal das selbe nur unter anderen Einstellungen, daher möchte ich für alle Diagramme eine gemeinsame Legende nutzten. Die soll mittig über dem mittleren Diagramm stehen und die Legendeneinträge nebeneinander auflisten.

Bislang hat das auch wunderbar funktioniert. Heute habe ich aber einen etwas längeren Namen für den Legendeneintrag vergeben und festgestellt, dass die Graphen dann nicht mehr nebeneinander passen, weil die Legende über das Diagramm übersteht.

Kann man die Legende sonst noch irgendwie erzeugen, z.B. außerhalb des mittleren Diagramms damit wieder alles nebeneinander angezeigt wird?
\documentclass[12pt, oneside, a4paper, listof=numbered, listof=leveldown]{scrreprt}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[english, ngerman]{babel}

\usepackage{tikz}

\usepackage{pgfplots}
\pgfplotsset{compat=newest,
			 width = 0.8\textwidth,
			 height = 0.3\textheight,
			 grid = none,
			 title style = { anchor = south, at = {(0.5,0)}, draw=black, fill=white },
			 every axis/.append style = {every node/.style = {{yshift = -8pt}, sloped}},
			 every x tick label/.append style = {text height = 2ex},
			 every tick/.append style = {scaled ticks = true},
			 every axis legend/.append style={at = {(0.5,1.05)},
											  anchor = south,
											  legend columns = -1,
											  no markers, 
											  nodes = {right, inner xsep=5pt},
											  shape = rectangle,
											  fill = white},
			 ybar/.append style = {every axis plot/.append style = {fill},
			 					   tick align = inside},
			 ybar interval/.append style = {every axis plot/.append style = {fill},
			 					   tick align = inside}
			 }

\begin{document}



\begin{figure}[H]
\begin{tikzpicture}	% Diagramm links

\pgfplotsset{
	ymajorgrids,
	width  = 0.3\textwidth,
	title = {Links}
	}

\begin{axis}[
	axis y line* = left,
	axis x line = none,
	ylabel = {Beschriftung links}
	]
\end{axis}

\begin{axis}[
	axis y line* = right,
	yticklabels = { }
	]
\end{axis}

\end{tikzpicture}
% keine Leerzeile, sonst sind Diagramme nicht nebeneinander
\begin{tikzpicture}	% Diagramm mitte

\pgfplotsset{
	ymajorgrids,
	width  = 0.3\textwidth,
	title = {Mitte},
	yticklabels = { }
	}

\begin{axis}[
	axis y line* = left,
	axis x line = none
	]
	\addplot [blue, smooth] {x};
	\label{legendeneintrag}
\end{axis}

\begin{axis}[
	axis y line* = right,
	]
	\addlegendimage{/pgfplots/refstyle=legendeneintrag}
	\addlegendentry{langer Eintrag}
	
	\addplot [cyan, smooth] {-x};
	\addlegendentry{noch ein langer Eintrag} 
\end{axis}

\end{tikzpicture}
% keine Leerzeile, sonst sind Diagramme nicht nebeneinander
\begin{tikzpicture}	% Diagramm rechts

\pgfplotsset{
	ymajorgrids,
	width  = 0.3\textwidth,
	title = {rechts}
	}

\begin{axis}[
	axis y line* = left,
	axis x line = none,
	yticklabels = { }
	]
\end{axis}

\begin{axis}[
	axis y line* = right,
	ylabel = {Beschriftung rechts},
	]
\end{axis}

\end{tikzpicture}
\end{figure}



\end{document}

feuersaenger
Forum-Fortgeschrittener
Forum-Fortgeschrittener
Beiträge: 91
Registriert: Mi 5. Okt 2011, 18:24
Wohnort: Rheinbach

Beitrag von feuersaenger »

Hi Chris,

es gibt da im Wesentlichen zwei Ansatzmoeglichkeiten.

Die mit weniger Anpassungsarbeit ist

1. Setze
legend style={overlay}
fuer die legende (d.h. in der Achse, wo Du die legende definierst). Damit wird die von der bounding box berechnung ausgeschlossen und nimmt gar keinen platz weg.

Dummerweise ueberschreibt sie dann jeglichen Text, der direkt ueber der Abbildung steht - was man normal nicht will. Das kann man aber leicht kompensieren, indem man darueber einen vspace einfuegt.

Dieser Ansatz koennte zu Problemen bei image externalisierung fuehren (denn dann wuerde die legend "aus dem externen bild fallen").

2. Du kannst
legend to name=chrislegendlabel
in der Achse setzen, die die legende definiert. Damit wird die legend _nicht_ gezeichnet, sondern lediglich "vermerkt".

Sobald Du dann irgendwo im Dokument
\ref{chrislegendlabel}
eingibst, wird an diese Stelle die legende gezeichnet.

Das ist robust und geht halbautomatisch auch mit image externalisierung. Du muesstest dann lediglich die horizontale Zentrierung "von Hand" machen (entweder ueber TeX builtin mittel wie \centering oder mithilfe von TikZ nodes).

Details zu beiden Ansaetzen findest Du im pgfplots manual in den Abschnitten zu Alignment (soweit es overlay betrifft) und zu Legenden (legend to name).

Mit liebem Gruss

Christian

chris_Waechter

Beitrag von chris_Waechter »

Hallo Chris und vielen Dank für den Tipp. Deine zweite Version funktioniert recht gut, aber nur solange ich die Externalisierung in der Präambel nicht anschalte. Kannst du dir das erklären?
\documentclass[12pt, oneside, a4paper, listof=numbered, listof=leveldown]{scrreprt}

\usepackage{floatrow}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[english, ngerman]{babel}

\usepackage{tikz}

\usepackage{pgfplots}
\pgfplotsset{compat=newest,
			 title style = { anchor = south, at = {(0.5,0)}, draw=black, fill=white },
			 every axis legend/.append style={at = {(0.5,1.05)},
											  anchor = south,
											  legend columns = -1,
											  no markers, 
											  nodes = {right, inner xsep=5pt},
											  shape = rectangle,
											  fill = white}
			 }

\usepgfplotslibrary{external}

% Erzeugt einen Fehler
%\tikzexternalize[prefix=complierteAbbildungen/]

\tikzset{external/system call={lualatex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource"}}

\begin{document}

\begin{figure}[H]

\pgfplotslegendfromname{gemeinsame_legende1}

\begin{tikzpicture}	% Diagramm links

\pgfplotsset{
	ymajorgrids,
	width  = 0.3\textwidth,
	title = {links}
	}

\begin{axis}[
	axis y line* = left,
	axis x line = none,
	ylabel = {Beschriftung rechts}
	]
\end{axis}

\begin{axis}[
	axis y line* = right,
	yticklabels = { }
	]
\end{axis}

\end{tikzpicture}
% keine Leerzeile, sonst sind Diagramme nicht nebeneinander
\tikzset{external/export next=false} % um Symbol von Legendeneintrag korrekt zu zeichnen
\begin{tikzpicture}	% Diagramm mitte

\pgfplotsset{
	ymajorgrids,
	width  = 0.3\textwidth,
	title = {mitte},
	yticklabels = { }
	}

\begin{axis}[
	axis y line* = left,
	axis x line = none
	]
	\addplot [blue, smooth] {-2*x};
	\label{data:Signal1}
\end{axis}

\begin{axis}[
	axis y line* = right,
	legend to name=gemeinsame_legende1
	]
	\addlegendimage{/pgfplots/refstyle=data:Signal1}
	\addlegendentry{langer Legendeneintrag}
	
	\addplot [cyan, smooth] {2*x};
	\addlegendentry{noch ein langer Legendeneintrag} 
\end{axis}

\end{tikzpicture}
% keine Leerzeile, sonst sind Diagramme nicht nebeneinander
\begin{tikzpicture}	% Diagramm rechts

\pgfplotsset{
	ymajorgrids,
	width  = 0.3\textwidth,
	title = {rechts}
	}

\begin{axis}[
	axis y line* = left,
	axis x line = none,
	yticklabels = {},
	]
\end{axis}

\begin{axis}[
	axis y line* = right,
	ylabel = {Beschriftung rechts}
	]
\end{axis}
\end{tikzpicture}
\caption{gemeinsame Beschriftung für alle drei Graphen}
\end{figure}

\end{document}

feuersaenger
Forum-Fortgeschrittener
Forum-Fortgeschrittener
Beiträge: 91
Registriert: Mi 5. Okt 2011, 18:24
Wohnort: Rheinbach

Beitrag von feuersaenger »

Hi Chris,

die image externalisierung wird speziell, wenn es um label/ref geht.

Langer rede kurzer Sinn ist: es funktioniert nicht mit dem standardmodus.

Du hast da zwei Optionen:

1. Du behaelst den standard externalisierungsmodus und musst dann aber den Befehl zur Externalisierung der legend "von Hand" eingeben.

Das ist nicht schwierig, nur umstaendlich:

Du schaust in Dein log file wo sowas wie
! Package tikz Error: Sorry, the system call 'lualatex -halt-on-error -interaction=batchmode -jobname "P-figure_crossref0" "\def\tikzexternalrealjob{P}\input{P}"' did NOT result in a usable output file 'P-figure_crossref0' (expected one of .pdf:.jpg:.jpeg:.png:). Please verify that you have enabled system calls. For pdflatex, this is 'pdflatex -shell-escape'. Sometimes it is also named 'write 18' or something like that. Or maybe the command simply failed? Error messages can be found in 'P-figure_crossref0.log'. If you continue now, I'll try to typeset the picture.
steht. Daraus kopierst Du von Hand den Befehl, in meinem Fall ist das
lualatex -halt-on-error -interaction=batchmode -jobname "P-figure_crossref0" "\def\tikzexternalrealjob{P}\input{P}"
Dann oeffnest Du eine Kommandozeile in dem Verzeichnis Deines Dokumentes (Windows explorer: rechts klick und dann "command shell here" oder so) und gibst diesen Befehl ein. Du kannst den Befehl auch in eine Datei "extra.bat" schreiben und diese durch doppelklick ausfuehren.

2. Die alternative geht unter linux fuer Experten gut, unter windows ist sie nix:
Es geht auch mit 'mode=list and make'. Falls Du weisst, was make ist, kannst Du das anwenden - ansonsten ist die Loesung vermutlich nur dann was, wenn Du auch linux benutzt.

Details dazu gibt es im Manual pgfmanual.pdf in dem Abschnitt zur Externalisierung.[/list]

PS.
Nur ein Hinweis, der vielleicht interessant ist:
Du musst nicht mehr
\tikzset{external/system call={lualatex...
eingeben: seit pgfplots 1.11 geht das automatisch.

chris_Waechter

Beitrag von chris_Waechter »

Guten Morgen,

die beiden von dir genannten Varianten finde ich zugegeben ziemlich umständlich, schade dass Latex oder PGFPlots da keine "Intelligenz" hat...

Ich habe aber noch ein wenig rumprobiert und scheinbar eine Lösung ohne Kommandozeile gefunden. Diese funktioniert in meinem Hauptdokument super, im Minimalbeispiel bekomme ich es aber nicht zum laufen.

Ich habe einfach den \pgfplotslegendfromname-Befehl in eine tikzpicture-Umgebung gepackt und die Externalisierung dafür abgeschalten. Wie gesagt, das Minimalbeispiel kann ich nicht kompilieren aber im Hauptdokument funktioniert es:
\documentclass[12pt, oneside, a4paper, listof=numbered, listof=leveldown]{scrreprt}

\usepackage{floatrow}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage[english, ngerman]{babel}

\usepackage{tikz}

\usepackage{pgfplots}
\pgfplotsset{compat=newest,
          title style = { anchor = south, at = {(0.5,0)}, draw=black, fill=white },
          every axis legend/.append style={at = {(0.5,1.05)},
                                   anchor = south,
                                   legend columns = -1,
                                   no markers,
                                   nodes = {right, inner xsep=5pt},
                                   shape = rectangle,
                                   fill = white}
          }

\usepgfplotslibrary{external}

\tikzexternalize[prefix=complierteAbbildungen/]
\tikzset{external/system call={lualatex \tikzexternalcheckshellescape -halt-on-error -interaction=batchmode -jobname "\image" "\texsource"}}

\begin{document}

\begin{figure}[H]

\tikzset{external/export next=false}
\begin{tikzpicture} 
\pgfplotslegendfromname{gemeinsame_legende1}
\end{tikzpicture} 

\begin{tikzpicture}   % Diagramm links

\pgfplotsset{
   ymajorgrids,
   width  = 0.3\textwidth,
   title = {links}
   }

\begin{axis}[
   axis y line* = left,
   axis x line = none,
   ylabel = {Beschriftung rechts}
   ]
\end{axis}

\begin{axis}[
   axis y line* = right,
   yticklabels = { }
   ]
\end{axis}

\end{tikzpicture}
% keine Leerzeile, sonst sind Diagramme nicht nebeneinander
\tikzset{external/export next=false} % um Symbol von Legendeneintrag korrekt zu zeichnen
\begin{tikzpicture}   % Diagramm mitte

\pgfplotsset{
   ymajorgrids,
   width  = 0.3\textwidth,
   title = {mitte},
   yticklabels = { }
   }

\begin{axis}[
   axis y line* = left,
   axis x line = none
   ]
   \addplot [blue, smooth] {-2*x};
   \label{data:Signal1}
\end{axis}

\begin{axis}[
   axis y line* = right,
   legend to name=gemeinsame_legende1
   ]
   \addlegendimage{/pgfplots/refstyle=data:Signal1}
   \addlegendentry{langer Legendeneintrag}
   
   \addplot [cyan, smooth] {2*x};
   \addlegendentry{noch ein langer Legendeneintrag}
\end{axis}

\end{tikzpicture}
% keine Leerzeile, sonst sind Diagramme nicht nebeneinander
\begin{tikzpicture}   % Diagramm rechts

\pgfplotsset{
   ymajorgrids,
   width  = 0.3\textwidth,
   title = {rechts}
   }

\begin{axis}[
   axis y line* = left,
   axis x line = none,
   yticklabels = {},
   ]
\end{axis}

\begin{axis}[
   axis y line* = right,
   ylabel = {Beschriftung rechts}
   ]
\end{axis}
\end{tikzpicture}
\caption{gemeinsame Beschriftung für alle drei Graphen}
\end{figure}

\end{document} 

feuersaenger
Forum-Fortgeschrittener
Forum-Fortgeschrittener
Beiträge: 91
Registriert: Mi 5. Okt 2011, 18:24
Wohnort: Rheinbach

Beitrag von feuersaenger »

Du hast Recht, das ist schon umstaendlich und unschoen.

Besser waere es, es wuerde sofort funktionieren... ist aber leider nicht so einfach.

Allerdings hat mich Deine Antwort daran erinnert, dass man generell die image externalisierung der \ref's ausschalten kann!

Das geht z.B. mithilfe folgender einfacher Konfiguration (global fuer alle):
\documentclass[12pt, oneside, a4paper, listof=numbered, listof=leveldown]{scrreprt}

\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}

\usepackage{tikz}

\usepackage{pgfplots}
\pgfplotsset{compat=newest,
          title style = { anchor = south, at = {(0.5,0)}, draw=black, fill=white },
          every axis legend/.append style={at = {(0.5,1.05)},
                                   anchor = south,
                                   legend columns = -1,
                                   no markers,
                                   nodes = {right, inner xsep=5pt},
                                   shape = rectangle,
                                   fill = white},
		  invoke before crossref tikzpicture={%
		  	\begingroup
		  	\tikzset{external/export next=false}%
		  }%
          }

\usepgfplotslibrary{external}

\tikzexternalize

\begin{document}

\begin{figure}[H]

\pgfplotslegendfromname{gemeinsame_legende1}

\begin{tikzpicture}   % Diagramm links

\pgfplotsset{
   ymajorgrids,
   width  = 0.3\textwidth,
   title = {links}
   }

\begin{axis}[
   axis y line* = left,
   axis x line = none,
   ylabel = {Beschriftung rechts}
   ]
\end{axis}

\begin{axis}[
   axis y line* = right,
   yticklabels = { }
   ]
\end{axis}

\end{tikzpicture}
% keine Leerzeile, sonst sind Diagramme nicht nebeneinander
\tikzset{external/export next=false} % um Symbol von Legendeneintrag korrekt zu zeichnen
\begin{tikzpicture}   % Diagramm mitte

\pgfplotsset{
   ymajorgrids,
   width  = 0.3\textwidth,
   title = {mitte},
   yticklabels = { }
   }

\begin{axis}[
   axis y line* = left,
   axis x line = none
   ]
   \addplot [blue, smooth] {-2*x};
   \label{data:Signal1}
\end{axis}

\begin{axis}[
   axis y line* = right,
   legend to name=gemeinsame_legende1
   ]
   \addlegendimage{/pgfplots/refstyle=data:Signal1}
   \addlegendentry{langer Legendeneintrag}
   
   \addplot [cyan, smooth] {2*x};
   \addlegendentry{noch ein langer Legendeneintrag}
\end{axis}

\end{tikzpicture}
% keine Leerzeile, sonst sind Diagramme nicht nebeneinander
\begin{tikzpicture}   % Diagramm rechts

\pgfplotsset{
   ymajorgrids,
   width  = 0.3\textwidth,
   title = {rechts}
   }

\begin{axis}[
   axis y line* = left,
   axis x line = none,
   yticklabels = {},
   ]
\end{axis}

\begin{axis}[
   axis y line* = right,
   ylabel = {Beschriftung rechts}
   ]
\end{axis}
\end{tikzpicture}
\caption{gemeinsame Beschriftung für alle drei Graphen}
\end{figure}

\end{document} 
Mit liebem Gruss

Christian

Antworten