Hallo Leute!

Wieder einmal habe ich eine Frage zu pgfplots und wieder ist es so, dass meine Zeichnung alleine als tex-file kompiliert genau so aussieht wie ich will und dann, eigebunden ins Dokument nicht mehr tut was sie soll. So funktioniert es:

Open in writeLaTeX
% Legende korrekt:
\begin{filecontents}{\jobname.csv}
2   224694229071385000  8.97    8.72    3.275
5   561735572678462000  8.25    5.25    4.91
10  1123471145356920000 8.5 4.92    4.92
30  3370413436070770000 7.75    3.5 6.19
60  6740826872141550000 7.09    4.5 5.82
120 13481653744283100000    6.85    4.75    6.06
\end{filecontents}
\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.10}
\usepackage{siunitx}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
   xlabel = {xlabel},
   ylabel = {ylabel 1},
   smooth,
   axis y line*=left, 
   scaled x ticks=false,
   xticklabel={\pgfmathprintnumber[sci,sci generic={mantissa sep=\times,exponent={10^{##1}}}]{\tick}},
   legend style={draw=none},
]
\addplot[black, mark =x] table [x index = 1, y index = 2] {\jobname.csv};
\label{label_1}
\addplot[red, mark =x] table [x index = 1, y index = 3] {\jobname.csv};
\label{label_2}
\end{axis}

\begin{axis}[
   ylabel = {Maximalwert [\SI{}{\percent}]},
   smooth,
   axis y line*=right, 
   xmajorticks=false,
   scaled x ticks=false, 
   legend style={draw=none},
]
\addlegendimage{/pgfplots/refstyle=label_1}\addlegendentry{\scriptsize{Name 1}};
\addlegendimage{/pgfplots/refstyle=label_2}\addlegendentry{\scriptsize{Name 2}};
\addplot[green, mark =x] table [x index = 1, y index = 4] {\jobname.csv};
\addlegendentry{\scriptsize{Name 3}};
\end{axis}
\end{tikzpicture}
\end{document}

Das Problem ist: Wenn ich das Bild Bild einzeln kompiliere ist alles schick. Wenn ich das Bild in mein Dokument einbinde, in dem ich die external Bibliothek für TikZ verwenden, dann wird die Legende der oberen axis Umgebung im Stil black und nicht in dem angegebenen Stil geplottet:

Open in writeLaTeX
% Legende nicht korrekt:
\RequirePackage{filecontents}
\begin{filecontents}{\jobname Data.asc}
2   224694229071385000  8.97    8.72    3.275
5   561735572678462000  8.25    5.25    4.91
10  1123471145356920000 8.5 4.92    4.92
30  3370413436070770000 7.75    3.5 6.19
60  6740826872141550000 7.09    4.5 5.82
120 13481653744283100000    6.85    4.75    6.06
\end{filecontents}
\documentclass{article}
\usepackage{pgfplots}
\pgfplotsset{compat=1.10}
\usepackage{siunitx}
\usepgfplotslibrary{external}
\tikzexternalize
\tikzsetexternalprefix{external_figs/}
\begin{document}
\begin{tikzpicture}
\begin{axis}[
   xlabel = {xlabel},
   ylabel = {ylabel 1},
   smooth,
   axis y line*=left, 
   xmin = -2e18,
   xmax = 1.6e19,
   scaled x ticks=false,
   xticklabel={\pgfmathprintnumber[sci,sci generic={mantissa sep=\times,exponent={10^{##1}}}]{\tick}},
   xtick = {0,5e18,1e19,1.5e19},   
   legend style={draw=none},
]
\addplot[black, mark =x] table [x index = 1, y index = 2] {\jobname Data.asc};
\label{1}
\addplot[red, mark =x] table [x index = 1, y index = 3] {\jobname Data.asc};
\label{2}
\end{axis}

\begin{axis}[
   ylabel = {ylabel 2},
   smooth,
   axis y line*=right, 
   xmin = -2e18,
   xmax = 1.6e19,
   ymin = 2.9,
   ymax = 7.2,   
   %ytick ={3,4,...,9},
   xmajorticks=false,
   scaled x ticks=false, 
   legend style={draw=none},
]
\addlegendimage{/pgfplots/refstyle=1}\addlegendentry{\scriptsize{name 1}};
\addlegendimage{/pgfplots/refstyle=2}\addlegendentry{\scriptsize{name 2}};
\addplot[green, mark =x] table [x index = 1, y index = 4] {\jobname Data.asc};
\addlegendentry{\scriptsize{name 3}};
\end{axis}
\end{tikzpicture}
\end{document}

Zwar gibt es bereits eine ähnliche Frage mit einer Antwort von @cfeuersaenger, ich weiß aber nicht, wie ich diese konkret auf mein Problem anwenden kann.

gefragt 25 Sep '14, 11:08

lorbj's gravatar image

lorbj
1392713
Akzeptiert-Rate: 33%

bearbeitet 26 Sep '14, 11:09

gast3's gravatar image

gast3
(ausgesetzt)


Man könnte den zusätzlich benötigten Aufruf auch automatisieren. Dazu patche ich die Bibliothek external so, dass sie zusätzlich zu dem normalen \write18-Aufruf auch noch einen weiteren \write18-Aufruf nach dem Einlesen der aux-Datei durchführt:

Open in writeLaTeX
\usepackage{scrlfile}
\usepackage{etoolbox}
\makeatletter
\newif\if@lateexternal
\newcommand*{\nextwithlateexternal}{\@lateexternaltrue}
\renewcommand*{\@lateexternalfalse}{\global\let\if@lateexternal\iffalse}
% Den Systemaufruf von external so ändern, dass er optional doppelt
% stattfindet: Zunächst wie gehabt unmittelbar und zusätzlich nachdem
% die aux-Datei geschlossen (und sogar neu gelesen) wurde.
\patchcmd\tikzexternal@externalizefig@systemcall@@
  {\immediate\write18{\pgf@tempa}}%
  {\immediate\write18{\pgf@tempa}%
    \if@lateexternal
      \begingroup
        \protected@edef\reserved@a{%
          \noexpand\endgroup
          \noexpand\AfterReadingMainAux{%
            \noexpand\immediate\noexpand\write18{%
              \expandafter\detokenize\expandafter{\pgf@tempa}}%
          }%
        }%
      \reserved@a
    \fi
  }%
  {}%
  {\patchFailedError}
% Nun dafür sorgen, dass der Aufruf \nextwithlateexternal nur auf
% den nächsten potentiellen Systemaufruf von external wirkt statt
% auf den nächsten tatsächlichen oder gar alle:
\apptocmd\tikzexternal@externalizefig@systemcall@@
  {\@lateexternalfalse}
  {}
  {\patchFailedError}
\makeatother

Erklärung: Der späte \write18-Aufruf erfolgt mit Hilfe der Anweisung \AfterReadingMainAux, die von scrlfile bereitgestellt wird. Für den Aufruf selbst greife ich dabei genau auf den Aufruf zurück, den external selbst durchführt. Dazu muss nur der Original-\write18-Aufruf erweitert werden. Ich muss damit nicht wissen, wie die externe Datei heißt, das ist alles in \pgf@tempa versteckt.

Außerdem habe ich einen Schalter eingebaut, damit man nur diejenigen Abbildungen doppelt durchlaufen lassen kann, die das wirklich benötigen. Das geht über \nextwithlateexternal unmittelbar vor der entsprechenden tikzpicture-Umgebung.

Insgesamt sieht das dann so aus:

Open in writeLaTeX
\RequirePackage{filecontents}
\begin{filecontents}{\jobname Data.asc}
2   224694229071385000  8.97    8.72    3.275
5   561735572678462000  8.25    5.25    4.91
10  1123471145356920000 8.5 4.92    4.92
30  3370413436070770000 7.75    3.5 6.19
60  6740826872141550000 7.09    4.5 5.82
120 13481653744283100000    6.85    4.75    6.06
\end{filecontents}
\documentclass{article}
\usepackage{scrlfile}
\usepackage{pgfplots}
\pgfplotsset{compat=1.10}
\usepackage{siunitx}
\usepgfplotslibrary{external}
\tikzexternalize
\tikzsetexternalprefix{external_figs/}

\usepackage{etoolbox}
\makeatletter
\newif\if@lateexternal
\newcommand*{\nextwithlateexternal}{\@lateexternaltrue}
\renewcommand*{\@lateexternalfalse}{\global\let\if@lateexternal\iffalse}
\patchcmd\tikzexternal@externalizefig@systemcall@@
  {\immediate\write18{\pgf@tempa}}%
  {\immediate\write18{\pgf@tempa}%
    \if@lateexternal
      \begingroup
        \protected@edef\reserved@a{%
          \noexpand\endgroup
          \noexpand\AfterReadingMainAux{%
            \noexpand\immediate\noexpand\write18{%
              \expandafter\detokenize\expandafter{\pgf@tempa}}%
          }%
        }%
      \reserved@a
    \fi
  }%
  {}%
  {\patchFailedError}
\apptocmd\tikzexternal@externalizefig@systemcall@@
  {\@lateexternalfalse}
  {}
  {\patchFailedError}
\makeatother

\begin{document}
\nextwithlateexternal% späte Externalisierung für nächstes tikzpicture aktivieren
\begin{tikzpicture}
\begin{axis}[
   xlabel = {xlabel},
   ylabel = {ylabel 1},
   smooth,
   axis y line*=left, 
   xmin = -2e18,
   xmax = 1.6e19,
   scaled x ticks=false,
   xticklabel={\pgfmathprintnumber[sci,sci generic={mantissa sep=\times,exponent={10^{##1}}}]{\tick}},
   xtick = {0,5e18,1e19,1.5e19},   
   legend style={draw=none},
]
\addplot[black, mark =x] table [x index = 1, y index = 2] {\jobname Data.asc};
\label{1}
\addplot[red, mark =x] table [x index = 1, y index = 3] {\jobname Data.asc};
\label{2}
\end{axis}

\begin{axis}[
   ylabel = {ylabel 2},
   smooth,
   axis y line*=right, 
   xmin = -2e18,
   xmax = 1.6e19,
   ymin = 2.9,
   ymax = 7.2,   
   %ytick ={3,4,...,9},
   xmajorticks=false,
   scaled x ticks=false, 
   legend style={draw=none},
]
\addlegendimage{/pgfplots/refstyle=1}\addlegendentry{\scriptsize{name 1}};
\addlegendimage{/pgfplots/refstyle=2}\addlegendentry{\scriptsize{name 2}};
\addplot[green, mark =x] table [x index = 1, y index = 4] {\jobname Data.asc};
\addlegendentry{\scriptsize{name 3}};
\end{axis}
\end{tikzpicture}
\end{document}

Nach dem ersten LaTeX-Lauf ist die Abbildung noch fehlerhaft:

noch fehlerhaft

Nach dem zweiten LaTeX-Lauf stimmt aber alles:

nach zwei Läufen

Da der von external auch für den ersten pdflatex-Lauf verwendete Aufruf kopiert wird, sollte das ganze unabhängig vom Betriebssystem sein. Damit es überhaupt funktioniert, muss aber natürlich external die Notwendigkeit eines neuen pdflatex-Laufs erkennen. Also bitte mit einem jungfräulichen external_figs-Verzeichnis testen!

Ein weiterer Vorteil der Lösung: Wann immer external den normalen externen pdflatex-Lauf durchführt, wird auch der zweite, späte pdflatex-Lauf automatisch durchgeführt. Erkennt external hingegen keine Notwendigkeit für den ersten Lauf, so entfällt auch automatisch der zweite.

Da die Lösung außerdem eine auf LaTeX-Ebene ist, ist sie auch unabhängig vom verwendeten Editor. Ideal wäre natürlich, wenn @cfeuersaenger eine solche Möglichkeit direkt in external einbauen würde, so dass man sie über einen TikZ-Schalter aktivieren könnte.

Einen Nachteil will ich aber nicht verschweigen: Gibt es im ersten von external durchgeführten pdflatex-Lauf einen Fehler, so wird der zweite trotzdem durchgeführt und der Fehler tritt ein zweites Mal auf.

Permanenter link

beantwortet 26 Sep '14, 10:26

gast3's gravatar image

gast3
(ausgesetzt)
Akzeptiert-Rate: 53%

bearbeitet 26 Sep '14, 12:11

Meine erste Lösung hatte leider nicht funktioniert, da dabei der zweite pdflatex-Lauf unmittelbar nach dem ersten durchgeführt wurde und dabei die Labels noch nicht in die aux-Datei geschrieben waren. Wird der zweite pdflatex-Lauf wie in der neuen Lösung erst nach der Fertigstellung der aux-Datei durchgeführt, funktioniert es.

(26 Sep '14, 10:38) gast3

Toll, danke!

(26 Sep '14, 12:21) lorbj

Die Ursache dieses Fehlers hat @cfeuersaenger in seiner Antwort auf die Frage Markierung in pgfplotlegende fehlerhaft übernommen erklärt.

Wie dort ebenfalls erläutert, kannst Du zum einen die Abbildung von der Externalisierung ausnehmen, dann kannst Du auch einfach nur \tikzset{external/export next=false} vor diese setzen. Alternativ können auch \tikzexternaldisable vor und \tikzexternalenable nach nicht zu externalisierenden Abbildungen einfügt werden. Nähere Infos zu diesen Befehlen findest Du im pgfmanual.

Zum anderen kannst Du die Abbildung trotzdem externalisieren, musst aber bei Änderungen an der Abbildung pdflatex -shell-escape <dateiname> zwei Mal ausführen und dazwischen zusätzlich noch für jede betroffene Abbildung

Open in writeLaTeX
pdflatex -shell-escape -halt-on-error -interaction=batchmode -jobname "<externalprefix><abbildungsname>" "\def\tikzexternalrealjob{<dateiname>}\input{<dateiname>}"

aufrufen. Dabei ist der Name der tex-Datei ohne Endung, <externalprefix> ist das Argument von \tikzsetexternalprefix. <abbildungsname> hat in der Voreinstellung die Struktur <dateiname>-figure<laufende nummer>, wobei die laufende Nummer bei 0 beginnt. Wenn das MWE aus der Frage den Dateinamen mwe.tex hat, dann lautet der Aufruf für das MWE

Open in writeLaTeX
pdflatex -shell-escape -halt-on-error -interaction=batchmode -jobname "external_figs/mwe-figure0" "\def\tikzexternalrealjob{mwe}\input{mwe}"

Ich habe das jetzt nur unter Windows getestet, vermute aber, dass das mit anderen Betriebssystemen genauso funktioniert.

Permanenter link

beantwortet 26 Sep '14, 01:17

esdd's gravatar image

esdd
17.7k254256
Akzeptiert-Rate: 62%

bearbeitet 26 Sep '14, 10:24

1

Funktioniert auch unter Linux allerdings muss man dann '…' statt "…" zum Quoten der Argumente verwenden oder die Backslashs verdoppeln.

(26 Sep '14, 07:47) gast3

Ich habe mein Beispiel jetzt in "mwe.tex" umbenannt, die Befehle kopiert, eingefügt und ausgeführt. Das Problem besteht weiterhin.

Edit: geht jetzt, im zweiten Quellcodekasten war ein Tippfehler, es muss "external_figs/mwe-figure0" statt "external_figs/LaTeX2-figure0" heißen.

(26 Sep '14, 08:40) lorbj

@lorbj Danke für den Hinweis. Den Tippfehler habe ich jetzt korrigiert.

(26 Sep '14, 10:24) esdd

Solange, bis die external Bibliothek für TikZ selbst eine Möglichkeit bietet, zwei statt nur einem externen Aufruf zu tätigen, kann man genau das mit folgendem Patch erreichen:

Open in writeLaTeX
\usepackage{etoolbox}
\makeatletter
\newif\if@twoexternalruns
\newcommand*{\nextwithtwoexternalruns}{\@twoexternalrunstrue}
\renewcommand*{\@twoexternalrunsfalse}{\global\let\if@twoexternalruns\iffalse}
\patchcmd\tikzexternal@externalizefig@systemcall@@
  {\immediate\write18{\pgf@tempa}}%
  {\immediate\write18{\pgf@tempa}%
    \if@twoexternalruns\@twoexternalrunsfalse\immediate\write18{\pgf@tempa}\fi}%
  {}{\patchFailed}
\makeatother

Nun kann man unmittelbar vor \begin{tikzpicture} mit \nextwithtwoexternalruns dafür sorgen, dass für genau diese nächste Umgebung automatisch zwei externe Aufrufe statt nur einem durchgeführt werden. Insgesamt sähe das dann also beispielsweise so aus:

Open in writeLaTeX
\RequirePackage{filecontents}
\begin{filecontents}{\jobname Data.asc}
2   224694229071385000  8.97    8.72    3.275
5   561735572678462000  8.25    5.25    4.91
10  1123471145356920000 8.5 4.92    4.92
30  3370413436070770000 7.75    3.5 6.19
60  6740826872141550000 7.09    4.5 5.82
120 13481653744283100000    6.85    4.75    6.06
\end{filecontents}
\documentclass{article}
\usepackage{scrlfile}
\usepackage{pgfplots}
\pgfplotsset{compat=1.10}
\usepackage{siunitx}
\usepgfplotslibrary{external}
\tikzexternalize
\tikzsetexternalprefix{external_figs/}

\usepackage{etoolbox}
\makeatletter
\newif\if@twoexternalruns
\newcommand*{\nextwithtwoexternalruns}{\@twoexternalrunstrue}
\renewcommand*{\@twoexternalrunsfalse}{\global\let\if@twoexternalruns\iffalse}
\patchcmd\tikzexternal@externalizefig@systemcall@@
  {\immediate\write18{\pgf@tempa}}%
  {\immediate\write18{\pgf@tempa}%
    \if@twoexternalruns\@twoexternalrunsfalse\immediate\write18{\pgf@tempa}\fi}%
  {}{\patchFailed}
\makeatother
\begin{document}
\nextwithtwoexternalruns
\begin{tikzpicture}
\begin{axis}[
   xlabel = {xlabel},
   ylabel = {ylabel 1},
   smooth,
   axis y line*=left, 
   xmin = -2e18,
   xmax = 1.6e19,
   scaled x ticks=false,
   xticklabel={\pgfmathprintnumber[sci,sci generic={mantissa sep=\times,exponent={10^{##1}}}]{\tick}},
   xtick = {0,5e18,1e19,1.5e19},   
   legend style={draw=none},
]
\addplot[black, mark =x] table [x index = 1, y index = 2] {\jobname Data.asc};
\label{1}
\addplot[red, mark =x] table [x index = 1, y index = 3] {\jobname Data.asc};
\label{2}
\end{axis}

\begin{axis}[
   ylabel = {ylabel 2},
   smooth,
   axis y line*=right, 
   xmin = -2e18,
   xmax = 1.6e19,
   ymin = 2.9,
   ymax = 7.2,   
   %ytick ={3,4,...,9},
   xmajorticks=false,
   scaled x ticks=false, 
   legend style={draw=none},
]
\addlegendimage{/pgfplots/refstyle=1}\addlegendentry{\scriptsize{name 1}};
\addlegendimage{/pgfplots/refstyle=2}\addlegendentry{\scriptsize{name 2}};
\addplot[green, mark =x] table [x index = 1, y index = 4] {\jobname Data.asc};
\addlegendentry{\scriptsize{name 3}};
\end{axis}
\end{tikzpicture}
\end{document}

Das schöne daran ist: Da genau der eine Aufruf der external Bibliothek verdoppelt wird, müsste es vollkommen unabhängig von Betriebssystem funktionieren.

Ich erhalte auf diesem Weg direkt:

Ergebnis nach dem ersten Lauf

In der log-Datei ist zu erkennen, dass auch tatsächlich zwei pdflatex-Aufrufe von external durchgeführt werden:

`===== 'mode=convert with system call': Invoking 'pdflatex -shell-escape -halt-o
n-error -interaction=batchmode -jobname "external_figs/test-figure0" "\def\tikz
externalrealjob{test}\input{test}"' ========
\openout3 = `test.auxlock'.

runsystem(pdflatex -shell-escape -halt-on-error -interaction=batchmode -jobname
 "external_figs/test-figure0" "\def\tikzexternalrealjob{test}\input{test}")...e
xecuted.

runsystem(pdflatex -shell-escape -halt-on-error -interaction=batchmode -jobname
 "external_figs/test-figure0" "\def\tikzexternalrealjob{test}\input{test}")...e
xecuted.

\openout3 = `test.auxlock'.`

Beim nächsten Lauf erkennt external außerdem, dass nichts zu tun ist, so dass beide Aufrufe entfallen.

Nachteil ist, dass bei Fehlern im TikZ-Code trotzdem zwei Aufrufe stattfinden, der Fehler also zweimal auftritt.

Permanenter link

beantwortet 26 Sep '14, 08:50

gast3's gravatar image

gast3
(ausgesetzt)
Akzeptiert-Rate: 53%

bearbeitet 26 Sep '14, 08:57

Deine Antwort
Vorschau umschalten

Folgen dieser Frage

Per E-Mail:

Wenn sie sich anmelden, kommen Sie für alle Updates hier in Frage

Per RSS:

Antworten

Antworten und Kommentare

Markdown-Grundlagen

  • *kursiv* oder _kursiv_
  • **Fett** oder __Fett__
  • Link:[Text](http://url.com/ "Titel")
  • Bild?![alt Text](/path/img.jpg "Titel")
  • nummerierte Liste: 1. Foo 2. Bar
  • zum Hinzufügen ein Zeilenumbruchs fügen Sie einfach zwei Leerzeichen an die Stelle an der die neue Linie sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Frage-Themen:

×728
×296
×32
×11
×5

gestellte Frage: 25 Sep '14, 11:08

Frage wurde gesehen: 16,588 Mal

zuletzt geändert: 26 Sep '14, 13:26