Das hier ist eine Nachfolgefrage zu dieser hier. Aufbauend auf Qrrbrbirlbels Antwort, hab ich etwas rumprobiert und wollte versuchen ein "dictionary" der Form {key1: (x1, y1), key2: (x2, y2),... mit Hilfe von pgfkeys so zu verarbeiten, dass ich die einzelnen x und y Koordinaten in eigene macros extrahiere um sie später nutzen zu können.

\documentclass{standalone}

\usepackage[svgnames]{xcolor}
\usepackage{tikz}
\usepackage{xstring}

\newcounter{coordcounter}
\setcounter{coordcounter}{23}

\pgfkeys{
  util/coord extractor/.style={
    util/@coord extractor/.list={#1}
  },
  util/@coord extractor/.code args={#1: #2}{
    \def\tempcoordkey{#1}
    \StrBetween{#2}{(}{)}[\coord]
    \pgfkeys{
      util/@@coord extractor/.list={\coord},
      bonds/counter/set={coordcounter}{23}
    }
  },
  util/@@coord extractor/.code={
    \pgfkeys{
      /bonds/counter/step={coordcounter}, 
      \savedpath/\tempcoordkey/\alph{coordcounter}={#1}
    }
  },
  bonds/counter/set/.code 2 args={\setcounter{#1}{#2}},
  bonds/counter/step/.code={\stepcounter{#1}},
  bonds/bond points/start/x/.store in={\startx},
  bonds/bond points/start/y/.store in={\starty},
  bonds/bond points/mid/x/.store in={\midx},
  bonds/bond points/mid/y/.store in={\midy},
  bonds/bond points/end/x/.store in={\endx},
  bonds/bond points/end/y/.store in={\endy},
  bonds/bond points/.code={
    \def\savedpath{/bonds/bond points}
    \pgfkeys{
      util/coord extractor={#1}
    }
  }
}

\begin{document}

\begin{tikzpicture}
  \pgfkeys{/bonds/bond points={start: (1, 2), mid: (3, 4), end: (5, 6)}}
  \draw (\startx, \starty) circle [radius=1cm];
  \draw (\midx, \midy) circle [radius=2cm];
\end{tikzpicture}

\end{document}

Während ich ein ähnliches Beispiel, bei dem die Koordinaten von { statt ( umhüllt sind und bei dem ich entsprechend auch keinen \StrBetween Befehl benötigt habe um die Koordinaten in eine Listenform zu bringen, zum Laufen bekommen habe, kann ich hier jedoch nicht verstehen, wo das Problem liegt. Ich habe stundenlang rumprobiert, ohne Erfolg. Auch aus der Fehlermeldung werde ich nicht schlauer. Wo ist das Problem bei der Benutzung von \StrBetween{#2}{(}{)}[\coord] um mir eine Liste für den .list handler zu erzeugen - ein Test des so erzeugten Makros \coord in einem \foreach Loop hat nämlich funktioniert und ich dachte beim .list handler werkelt eben ein solcher \foreach Loop im Hintergrund.

gefragt 11 Sep '13, 08:58

carlton87's gravatar image

carlton87
2541411
Akzeptiert: 100%

bearbeitet 11 Sep '13, 09:08


Das ürsprüngliche Problem ist, dass

start: (1, 2), mid: (3, 4), end: (5, 6)

vom .list-Handler (bzw. der internen \foreach-Schleife) in folgende Elemente aufgeteilt wird:

  • start: (1,
  • 2),
  • mid: (3,
  • 4),
  • end: (5 und
  • 6).

Das geht beim ersten Element noch gut, weil es dem Argumentenformat #1: #2 noch entspricht; 2) passt aber nicht mehr in #1: #2 rein. Dass \StrBetween auch keine gescheiten Ergebnisse mehr auswirft, brauche ich glaube ich nicht mehr zu erwähnen.

Also, beschützen wir das doofe Komma eben und schmeißen nochmal ein Paar { } außenrum:

\pgfkeys{/bonds/bond points={start: {(1, 2)}, mid: {(3, 4)}, end: {(5, 6)}}}

Fast! Die zwei Koordinaten werden nur als eine Einheit betracht (und die y-Macros gar nicht definiert). Der Haken:

util/@@coord extractor/.list={\coord}

Wieviele Elemente in der Liste siehst du? Ich sehe nur einen: \coord. Und \foreach sieht auch nur einen: Es wird nur über ein Element iteriert: \coord. \startx wird dann definiert als

\def\startx{\coord}

was zu zwei Problemen führt:

  1. \starty ist selbstverständlich gar nicht definiert, aber theoretisch kannst du dann auch gleich

    \draw (\startx) circle [radius=1cm] node {\startx};
    

    schreiben.

  2. Wenn mid: und end: bearbeitet wurde, expandiert \coord zu 5, 6, und da \startx zu \coords expandiert, expandiert es auch zu 5, 6. Es werden also alle Kreise an der gleichen Stelle gezeichnet.

Bezugnehmend auf:

Wo ist das Problem bei der Benutzung von \StrBetween{#2}{(}{)}[\coord] um mir eine Liste für den .list handler zu erzeugen - ein Test des so erzeugten Makros \coord in einem \foreach Loop hat nämlich funktioniert und ich dachte beim .list handler werkelt eben ein solcher \foreach Loop im Hintergrund.

Ja, hinter .list werkelt eine komplexe \foreach-Loop, allerdings kennt das offizielle \foreach eben die zwei Alternativen:

\foreach \var/\iab/\len in {Ele/men/t 1, Ele/men/t 2, …, Ele/men/t n}

und

\foreach \var/\iab/\len in \macroDasNachEinerExpansionEineListeDerElementeLiefert

Der .list-Handler arbeitet nur mit der ersten Option.

Lösung: \coord einmal (und da wir ja nur plain Zahlen haben könnten wir es theoretisch auch mehrmals) expandieren:

util/@@coord extractor/.list/.expand once=\coord

Aber: Warum denn so kompliziert?

Benutze doch direkt Keys start, mid und end, um die Koordinaten zu speichern. (Wenn dir der Doppelpunkt als Trenner so wichtig ist, könntest du xstring vorher auch drüber laufen lassen und alle : durch = austauschen, bevor es PGFkeys bearbeitet.

Ich vermeide auch, die etwas altbackenen /.store in-Keys und verwende den besseren .initial-Handler. Siehe dazu bitte auch die Fragen

auf TeX.sx.

Ein paar Styles dazu und man kann die Grafik schon beachtlich beeinflussen. (Bitte beachte, dass Kommas in den Koordinaten selbstverständlich immer noch beschützt werden müssen, wie ich das bei der Initialisierung auch gemacht habe.)

Code (original)

\documentclass{standalone}

\usepackage[svgnames]{xcolor}
\usepackage{tikz}
\usepackage{xstring}

\newcounter{coordcounter}
\setcounter{coordcounter}{23}

\pgfkeys{
  util/coord extractor/.style={
    util/@coord extractor/.list={#1}
  },
  util/@coord extractor/.code args={#1: #2}{%
    \def\tempcoordkey{#1}%
    \StrBetween{#2}{(}{)}[\coord]%
    \pgfkeys{
      util/@@coord extractor/.list/.expand once=\coord,
      bonds/counter/set={coordcounter}{23}
    }%
  },
  util/@@coord extractor/.code={%
    \pgfkeys{
      /bonds/counter/step={coordcounter},
      \savedpath/\tempcoordkey/\alph{coordcounter}={#1}
    }%
  },
  bonds/counter/set/.code 2 args={\setcounter{#1}{#2}},
  bonds/counter/step/.code={\stepcounter{#1}},
  bonds/bond points/start/x/.store in={\startx},
  bonds/bond points/start/y/.store in={\starty},
  bonds/bond points/mid/x/.store in={\midx},
  bonds/bond points/mid/y/.store in={\midy},
  bonds/bond points/end/x/.store in={\endx},
  bonds/bond points/end/y/.store in={\endy},
  bonds/bond points/.code={%
    \def\savedpath{/bonds/bond points}%
    \pgfkeys{
      util/coord extractor={#1}
    }%
  }
}

\begin{document}
\begin{tikzpicture}
  \pgfkeys{/bonds/bond points={start: {(1, 2)}, mid: {(3, 4)}, end: {(5, 6)}}}
  \draw (\startx, \starty) circle [radius=1cm] node {\startx, \starty};
  \draw (\midx, \midy) circle [radius=2cm] node {\midx, \midy};
  \draw (\endx, \endy) circle [radius=.5cm] node {\endx, \endy};
\end{tikzpicture}
\end{document}

Output (original)

alt text

Code

\documentclass[tikz]{standalone}
\newcommand*\bondset{\pgfqkeys{/bonds}}
\bondset{
  bond points/start/.initial={(0,0)},
  bond points/mid/.initial={(1,1)},
  bond points/end/.initial={(2,2)}}
\tikzset{bonds/.code={\bondset{#1}}}
\newcommand*{\drawBond}[1][]{%
  \begingroup
    \bondset{#1}%
    \draw[/bonds/every bond/.try, /bonds/start/.try] \pgfkeysvalueof{/bonds/bond points/start} circle [] node {start};
    \draw[/bonds/every bond/.try, /bonds/mid/.try]   \pgfkeysvalueof{/bonds/bond points/mid}   circle [] node {mid};
    \draw[/bonds/every bond/.try, /bonds/end/.try]   \pgfkeysvalueof{/bonds/bond points/end}   circle [] node {end};
  \endgroup}

\begin{document}
\begin{tikzpicture}[radius=+1cm]
\drawBond[mid/.style={green, radius=.5cm}]
\end{tikzpicture}
\begin{tikzpicture}[bonds={every bond/.append style={radius=+1cm}}]
\drawBond[
  bond points/mid=(45:1),
  bond points/end=(45+90:1),
  end/.style={red, radius=+.5cm}]
\end{tikzpicture}
\end{document}

Output

alt textalt text

Permanenter link

beantwortet 11 Sep '13, 09:55

Qrrbrbirlbel's gravatar image

Qrrbrbirlbel
2.9k1415

bearbeitet 11 Sep '13, 10:12

Oh je, viel zu lernen ich noch hab... Vielen Dank für die ausführliche Antwort und auch für den Hinweis, wie ich die "altbackenen" .store ins vermeiden kann (das kam mir auch nie so richtig elegant vor, aber es war der einfachste Weg zum Ziel). Leider ist meine Vorstellung davon wie was genau expandiert sehr begrenzt, weil ich gerade erst anfange mir über die etwas "TeXnischeren" Aspekte von LaTeX Gedanken zu machen, deshalb werden wohl noch häufiger Fragen zu meinen stümperhaften Versuchen mit pgfkeys umzugehen von mir kommen.

(11 Sep '13, 10:32) carlton87

Könntest Du mir sagen, warum du in deinem letzten Codebeispiel die TikZ Befehle innerhalb des neu definierten \drawBond Befehls mit \begingroup und \endgroup umhüllt hast?

(11 Sep '13, 22:54) carlton87

@carlton Das ist deshalb vorhanden, damit die gesetzten Styles und Keys lokal zu der Anwendung von \drawBond ist. Das macht TikZ quasi überall: Alles was zu beim \path angibst, ist ja auch nur während dieses Pfades gültig. So kannst du sehr einfach allgemeingültige Styles oder Ähnliches setzen und musst dann nur noch das, was sich ändert, angeben.

(12 Sep '13, 17:18) Qrrbrbirlbel
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

Aktuelle Buch-Infos

LaTeX Cookbook

LaTeX Beginners Guide

Limitierter Rabatt ebook
50% Coupon code tDRet6Y

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:

×3
×2

Frage gestellt: 11 Sep '13, 08:58

Frage wurde angeschaut: 1,946 Mal

Zuletzt aktualisiert: 12 Sep '13, 17:18