Anschlussfrage zu

https://texwelt.de/wissen/fragen/22892/pgfplots-patch-table-plot-mehrfache-beschriftung-bei-nodes-near-coords-durch-patch-table-with-point-meta


Im o.g. Thread wird eine Mehrfachbennung von nodes near coords durch eine Schleifenmethode von @murmeltier verwendet.

Ich möchte hierbei die Koordinatentabelle um einen Anker für die Textposition erweitern.

Öffne in Overleaf
% Koordinatentabelle
    table[header=true, x index=1, y index=2, row sep=\\] {
    Nr x y  Testposition\\
    0 0 0     south        \\  % 0. Aliaspunkt. SOLL:  south als Default
    1 1 0                    \\
    2 0 1       north       \\ % Ausnahme
    3 1 1                      \\ 
    };

Leider wird dabei nur letzte angebene Anker verwendet north. Eigentlich sollen die nodes near coords standardmäßig oberhalb der Punkte stehen, nur in angegeben Ausnahmefällen unterhalb.

alt text

Öffne in Overleaf
\documentclass[margin=5mm, tikz]{standalone}
\usepackage{pgfplots}
\usepgfplotslibrary{patchplots}
\pgfplotsset{compat=1.13}

% Methode festlegen, die Mehrfachplatzierung (je nach Pfadanzahl) 
% von Punktbezeichnungen verhindert ============
\xdef\LstPN{0}
\newif\ifDupe
\pgfplotsset{avoid dupes/.code={\Dupefalse
\foreach \X in \LstPN
{\pgfmathtruncatemacro{\itest}{ifthenelse(\X==\punktnummer,1,0)
% Geht natürlich nicht
%\pgfmathsetmacro{\Ankertest}{ifthenelse(\anker="north","north","south")
}
\ifnum\itest=1
\global\Dupetrue
\breakforeach
\fi}
\ifDupe
% auskommentieren: 
\typeout{\punktnummer\space ist\space ein\space Duplikat!}%
\xdef\punktnummer{} %macht mehrfache Nummern einfach unsichtbar
%\pgfkeysalso{/tikz/anchor=\anker} % geht auch nicht
\else
\xdef\LstPN{\LstPN,\punktnummer}
\fi}}
% ============

\begin{document}

\begin{tikzpicture}
\begin{axis}[hide axis]
\addplot+[
table/row sep=newline, 
patch, % Plot-Typ
patch type=polygon,
vertex count=2, % damit nur Kanten, keine Flächen, gezeichnet werden
%
% Angabe der Verbindungskanten =====================
patch table with point meta={
Startpkt Endpkt colordata  \\
%0 0 \\
1 1 \\
2 2 \\
3 3  \\% Bis hierhin ok....
1 3 \\% Ab hier wird überschrieben
1 2  \\
},
%
% Beschriftung
visualization depends on={value \thisrowno{0} \as \punktnummer},
visualization depends on={value \thisrowno{3} \as \anker},
every node near coord/.append style={
%anchor=\anker,
/pgfplots/avoid dupes,% Methode für Mehrfachplatzierung anwenden
},
nodes near coords={\punktnummer, \anker},
% Geht nicht
nodes near coords style={
anchor=\anker
},
]
% Koordinatentabelle
table[header=true, x index=1, y index=2, row sep=\\] {
Nr x y  Testposition\\
0 0 0     south        \\  % 0. Aliaspunkt. SOLL:  south als Default
1 1 0                    \\
2 0 1       north       \\ % Ausnahme
3 1 1                      \\ 
};
\end{axis}
\end{tikzpicture}
\end{document}

gefragt 17 Sep, 14:36

cis's gravatar image

cis
8.5k16174276
Akzeptiert: 68%

bearbeitet 18 Sep, 16:11

Ja, dann geht es "nur so". Aber das kann höchstens noch @Murmeltier, weil es eine einfache Ergänzung seines Unterprogramms sein dürfte; ich die ich gerade nicht komme.

(18 Sep, 13:59) cis

Ich habe nodes near coords={\punktnummer, \anker} ergänzt damit das Problem sichtbar wird.

(18 Sep, 16:11) cis

Das ist keine richtige Antwort, aber ein Erklärungsversuch, was bei Deinem Versuch schief läuft. (Und naja, in dem Beispiel ist das Ergebnis korrekt.)

Was läuft schief? Die Koordinaten werden in einem Loop über die erste Tabelle erzeugt. Zumindest macht Dein Code das so, und aus Gründen, die ich nicht 100% verstehe, willst Du das so. Ansonsten gäbe es ja das Problem der Duplikate nicht. Bitte korrigiere mich, wenn das nicht stimmt: Du willst im Prinzip in der zweiten Tabelle einen riesigen Datensatz hinterlegen, aber nur die Koordinaten markieren, die auch wirklich in irgendwelche patches eingebaut sind, oder? (Ansonsten könnten wir uns den ganzen Zauber sparen, indem wir die nodes near coords einfach in einem Loop über die zweite Tabelle generieren. Dazu später etwas mehr.)

Wo ist das Problem? Aus irgendwelchen Gründen, die ich nicht verstehe, wird, wenn pgfplots die Daten aus der zweiten Tabelle ausliest, die Information über den Anker schlicht ignoriert. M.a.W. die zur Punktnummer gehörigen Koordinaten werden ausgelesen/aktualisiert, nicht aber der Anker. Das wird mit dem ersten typeout für neue Koordinaten gezeigt. Der untige Code gibt die typeouts

Öffne in Overleaf
1 ist neu mit urprgl. Anker=north
1 ist neu mit Anker=north
1 ist ein Duplikat!
2 ist neu mit urprgl. Anker=north
2 ist neu mit Anker=south
2 ist ein Duplikat!
3 ist neu mit urprgl. Anker=north
3 ist neu mit Anker=south
3 ist ein Duplikat!
1 ist ein Duplikat!
1 ist ein Duplikat!
1 ist ein Duplikat!
1 ist ein Duplikat!

Wie Du siehst, variiert die Punkntnummer, nicht aber der ursprüngliche Anker. Und das, obwohl beide mit visualization depends on ausgelesen werden. (Dass wir beide völligen Unsinn machen, halte ich für unwahrscheinlich, weil ja ein Anker "north" ausgelesen wird.)

Wie kommt man hier weiter? Ich habe einfach eine Liste \LstExcept eingeführt, in der die Punktnummern gelistet sind, bei denen der Anker anders gesetzt werden soll. D.h., wenn Du einen riesigen Datensatz hast, aber nur ein paar Ausnahmen, dann ist diese Methode effizient. Du kannst Dir dann die Spalte "Textposition" sparen.

Hier ist der Code:

Öffne in Overleaf
\documentclass[margin=5mm, tikz]{standalone}
\usepackage{pgfplots}
\usepgfplotslibrary{patchplots}
\pgfplotsset{compat=1.13}

% Methode festlegen, die Mehrfachplatzierung (je nach Pfadanzahl) 
% von Punktbezeichnungen verhindert ============
\xdef\LstPN{0}
\newif\ifDupe
\pgfplotsset{avoid dupes/.code={\Dupefalse
\foreach \X in \LstPN
{\pgfmathtruncatemacro{\itest}{ifthenelse(\X==\punktnummer,1,0)
% Geht natürlich nicht
%\pgfmathsetmacro{\Ankertest}{ifthenelse(\anker="north","north","south")
}
\ifnum\itest=1
\global\Dupetrue
\breakforeach
\fi}
\ifDupe
% auskommentieren: 
\typeout{\punktnummer\space ist\space ein\space Duplikat!}%
%\xdef\punktnummer{} %macht mehrfache Nummern einfach unsichtbar
\pgfkeysalso{/tikz/opacity=0} % geht auch nicht
\else
\xdef\LstPN{\LstPN,\punktnummer}
\typeout{\punktnummer\space ist\space neu\space mit\space urprgl.\space Anker=\anker}
\foreach \X in \LstExcept
{\ifnum\X=\punktnummer
\pgfkeysalso{/tikz/anchor=-90}
\xdef\anker{south}
\fi}
%\pgfmathsetmacro{\anker}{\LstAnker[\punktnummer]}
\typeout{\punktnummer\space ist\space neu\space mit\space Anker=\anker}
\fi}}
% ============

\begin{document}
\xdef\LstExcept{2,3}
\begin{tikzpicture}
\begin{axis}[hide axis]
\addplot+[
table/row sep=newline, 
patch, % Plot-Typ
patch type=polygon,
vertex count=2, % damit nur Kanten, keine Flächen, gezeichnet werden
%
% Angabe der Verbindungskanten =====================
patch table with point meta={
Startpkt Endpkt colordata  \\
%0 0 \\
1 1 \\
2 2 \\
3 3  \\% Bis hierhin ok....
1 3 \\% Ab hier wird überschrieben
1 2  \\
},
%
% Beschriftung
visualization depends on={value \thisrowno{0} \as \punktnummer},
visualization depends on={value \thisrowno{3} \as \anker},
every node near coord/.append style={
%anchor=\anker,
/pgfplots/avoid dupes,% Methode für Mehrfachplatzierung anwenden
},
nodes near coords={\punktnummer},
% Geht nicht
nodes near coords style={
anchor=\anker
},
]
% Koordinatentabelle
table[header=true, x index=1, y index=2, row sep=\\] {
Nr x y  Testposition\\
0 0 0     south        \\  % 0. Aliaspunkt. SOLL:  south als Default
1 1 0       south             \\
2 0 1       north       \\ % Ausnahme
3 1 1                      \\ 
};
\end{axis}
\end{tikzpicture}
\end{document}

alt text

KOMMENTAR: Falls es irgendwie so sein sollte, dass man die Spalte Positionierung nicht wirklich auslesen kann, kannst Du evtl. \LstPN recyceln. Die beinhaltet ja alle tatsächlich verwendeten Punkte. D.h. Du kannst Dir die ganzen nodes near coords hier sparen und dann in einem zweiten Schritt über die die Liste loopen und die Nodes setzen. (Und ich kann mir einen weiteren Kommentar nicht ganz verkneifen. Wer immer die Frage gedownvoted hat: ich denke nicht, dass das ganz OK ist, m.E. wird hier ein merkwürdiges Verhalten von pgfplots aufgezeigt.)

ADDENDUM: Ich kann die Spalte "Textposition" problemlos entfernen. Dieser Code ist etwas flexibler.

Öffne in Overleaf
\documentclass[margin=5mm, tikz]{standalone}
\usepackage{pgfplots}
\usepgfplotslibrary{patchplots}
\pgfplotsset{compat=1.13}

% Methode festlegen, die Mehrfachplatzierung (je nach Pfadanzahl) 
% von Punktbezeichnungen verhindert ============
\xdef\LstPN{0}
\newif\ifDupe
\pgfplotsset{avoid dupes/.code={\Dupefalse
\foreach \X in \LstPN
{\pgfmathtruncatemacro{\itest}{ifthenelse(\X==\punktnummer,1,0)
% Geht natürlich nicht
%\pgfmathsetmacro{\Ankertest}{ifthenelse(\anker="north","north","south")
}
\ifnum\itest=1
\global\Dupetrue
\breakforeach
\fi}
\ifDupe
% auskommentieren: 
\typeout{\punktnummer\space ist\space ein\space Duplikat!}%
%\xdef\punktnummer{} %macht mehrfache Nummern einfach unsichtbar
\pgfkeysalso{/tikz/opacity=0} % geht auch nicht
\else
\xdef\anker{north}
\xdef\LstPN{\LstPN,\punktnummer}
\foreach \X/\neueranker in \LstExcept
{\typeout{\X/\neueranker}
\ifnum\X=\punktnummer
\xdef\anker{\neueranker}
\fi}
%\pgfmathsetmacro{\anker}{\LstAnker[\punktnummer]}
\typeout{\punktnummer\space ist\space neu\space mit\space Anker=\anker}
\pgfkeysalso{/tikz/anchor=\anker}
\fi}}
% ============

\begin{document}
\xdef\LstExcept{{2/-90},{3/0}}
\begin{tikzpicture}
\begin{axis}[hide axis]
\addplot+[
table/row sep=newline, 
patch, % Plot-Typ
patch type=polygon,
vertex count=2, % damit nur Kanten, keine Flächen, gezeichnet werden
%
% Angabe der Verbindungskanten =====================
patch table with point meta={
Startpkt Endpkt colordata  \\
%0 0 \\
1 1 \\
2 2 \\
3 3  \\% Bis hierhin ok....
1 3 \\% Ab hier wird überschrieben
1 2  \\
},
%
% Beschriftung
visualization depends on={value \thisrowno{0} \as \punktnummer},
every node near coord/.append style={
/pgfplots/avoid dupes,% Methode für Mehrfachplatzierung anwenden
},
nodes near coords={\punktnummer},
% Geht nicht
nodes near coords style={
anchor=\anker
},
]
% Koordinatentabelle
table[header=true, x index=1, y index=2, row sep=\\] {
Nr x y \\
0 0 0  \\  % 0. Aliaspunkt. SOLL:  south als Default
1 1 0  \\
2 0 1  \\ % Ausnahme
3 1 1  \\ 
};
\end{axis}
\end{tikzpicture}
\end{document}

alt text

Permanenter link

beantwortet 18 Sep, 21:20

Murmeltier's gravatar image

Murmeltier
2.0k64

bearbeitet 19 Sep, 13:58

Öhmm, also erstmal danke. Aber verstehe ich das richtig, dass bei 1000 Punkten auch \xdef\LstAnker{{90,90,-90,-90,-90}} 1000 Einträge haben müsste? Das ist dann für die Praxis nichts.

Aber mir ist hier die Idee gekommen, dass man (leicht weniger elegant) die Spalte Textposition durch Ankerwinkel 90 / -90 ersetzen könnte. Aber vermutlich wird es auch damit nicht reibungslos funktionieren.

(18 Sep, 21:54) cis

@cis Wie gesagt, die Liste der tatsächlich benötigten Koordinaten ist in \LstPN hinterlegt. Es ist gut möglich, dass wir etwas übersehen haben, und dass man doch die Anker irgendwie hinbekommt. Aber falls das nicht der Fall ist, sehe ich folgende Möglichkeiten: 1. Während des Zeichnens der patches nur zu protokollieren, welche Punkte tatsächlich gebraucht werden, und die dann in einem separaten Durchlauf mit Punktnummern versehen. Das wird vermutlich einigermassen flott sein. 2. In dem jetzigen Code die Platzierung mit einem separaten Aufruf aus der Tabelle auslesen. -> Langsam.

(18 Sep, 23:26) Murmeltier

Also ich habe einen Punkt ergänzt

Nr x y 4 2 2

und dann kam Array index out of bounds. (in '{-90,90,-90,-90}[4]'). Erst als ich "\xdef\LstAnker{{-90,90,-90,-90,30}}" erweiterte ging es wieder. Wenn ich jetzt also 1000 Punkte ergänze..... Mmmhhhh...

(19 Sep, 10:53) cis

@cis Das verstehe ich Alles. Mein Post oben startet mit "Das ist keine richtige Antwort, aber ein Erklärungsversuch, was bei Deinem Versuch schief läuft.". Wie gesagt, unter der Annahme, dass wir es nicht hinbekommen, dass der Anker beim Durchlauf aktualisiert wird, kann man die beiden Ideen von meinem obigen Kommentar verwenden. Oder, wenn es wirklich nur ein paar Anker gibt, die anders gesetzt werden sollen, kann man einfach eine Liste dieser Punkte erstellen, sagen wir \xdef\LstExcept{{3,17,391}} in der grossen Liste und dann überprüfen, ob die Punktnummer in der Liste ist.

(19 Sep, 12:58) Murmeltier

@Murmeltier Also mir kam noch die (erfolglos versuchte) Idee, einfach zwei Anker zu verwenden \xdef\LstAnker{{-90,90}} und dann

\pgfmathsetmacro{\anker}{\LstAnker[0]}% oder [1] \pgfkeysalso{/tikz/anchor=\anker}

Aber da wärst Du sicher selbst drauf gekommen; und falls es so ginge, hättest Du es gemacht.

(19 Sep, 13:06) cis

@cis Ich habe jetzt den Code überarbeitet. Du musst nur eine Liste erstellen, in der die Punkte gelistet sind, wo der Anker anders gesetzt werden soll.

(19 Sep, 13:09) Murmeltier

Ja sehr gut! Also an sich ist doch die Splate Textposition überflüssig geworden. north ist Default, Ausnahe \LstExcept ist south. Doch schaffe ich es gerade nicht die Spalte zu eliminieren....

(19 Sep, 13:31) cis

Kann es sein, dass Du visualization depends on={value \thisrowno{3} \as \anker}, behalten hast? Übrigens kann man das sehr einfach auf beliebige Anker verallgemeinern: nimm einfach \xdef\LstExcept{{2/-90},{3/-180}} oder so was und dann \foreach \X/\newanchor in \LstExcept {\ifnum\X=\punktnummer \pgfkeysalso{/tikz/anchor=\newanchor} \fi}.

(19 Sep, 13:51) Murmeltier

Ich glaube, ich habe es geschafft:

\pgfplotsset{avoid dupes/.code={\Dupefalse \xdef\anker{south} % an der Stelle ergänzt - ALS DEFAULT

dann kann ich %visualization depends on={value \thisrowno{3} \as \anker} auskommentieren, mithin auf die Spalte Textposition verzichten.

(19 Sep, 13:58) cis
1

@cis Ja, so ähnlich habe ich es in dem unteren Code auch gemacht.

(19 Sep, 14:14) Murmeltier
1

Super! Du kriegst von den Streichholzgraphern das goldene Streichholz verliehen.

(19 Sep, 14:24) cis
Ergebnis 5 von 11 Alle anzeigen
Deine Antwort auf die Frage (nicht auf andere Antworten)
Knebel-Vorschau

Folge dieser Frage

Per E-Mail:

Wenn Du Dich anmeldest, kannst Du Updates hier abonnieren

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üge einfach zwei Leerzeichen an die Stelle ein, an der die neue Zeile sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Zugeordnete Themen:

×263
×69
×8
×3

Frage gestellt: 17 Sep, 14:36

Frage wurde angeschaut: 378 Mal

Zuletzt aktualisiert: 19 Sep, 14:24