
Ich habe den folgenden TikZ-Code und frage mich, ob er optimiert werden kann? (Ich bin mir eigentlich sicher, dass das möglich ist!)
Das Hauptproblem ist folgendes: Wenn ich die erste Gruppe von Knoten, die von der Ellipse umgeben sind, drehe, um die zweite Gruppe zu erstellen, ist die Ellipse nicht am richtigen Platz. (Sie ist nicht dort, wo ich sie erwarte. Ich bin nicht sicher, welcher Punkt bei der Drehung fixiert ist.) Ich muss sie blind anpassen, um sie an die gewünschte Stelle zu verschieben.
Dasselbe gilt für die Beschriftungen „Community 2“ und „Community 3“. Die gedrehten Koordinaten scheinen nicht mit meinen Erwartungen übereinzustimmen, und ich muss sie blind mit begrenztem Erfolg anpassen.
Eine Anmerkung, die nichts damit zu tun hat: Ich habe auch mit For-Schleifen experimentiert, aber da ich möchte, dass die Kanten in jeder Community leicht unterschiedlich sind, scheint ein direktes Kopieren und Einfügen einfacher zu sein?
Auch andere Optimierungen sind willkommen.
Code
\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}[scale = 1,node distance = 10mm]
\tikzset{
every node/.append style={circle, thick,
inner sep=0pt, minimum size = 3mm},
every label/.append style={red},
c1/.style={draw=blue!50,fill=blue!20},
c2/.style={draw=green!80,fill=green!40},
c3/.style={draw=red!80,fill=red!40}
}
\filldraw[rotate=30,blue!10] (0.8,0.1) ellipse (30pt and 25pt);
\node at (1,1.7) {Community 1};
\node[c1] (1) at (0,0) {};
\node[c1] (2) at (1,1) {}
edge (1);
\node[c1] (3) at (0.7,0.2) {}
edge (2)
edge (1);
\node[c1] (4) at (0.2,0.7) {}
edge (3)
edge (2);
\node[c1] (5) at (1.3,0.5) {}
edge (2)
edge (4);
\begin{scope}[yshift=-2cm,rotate around={-40:(0,0)}]
\filldraw[rotate=30,green!10] (0.8,0.1) ellipse (30pt and 25pt);
\node at (1.2,-0.2) {Community 2};
\node[c2] (A) at (0,0) {};
\node[c2] (B) at (1,1) {}
edge (A);
\node[c2] (C) at (0.7,0.2) {}
edge (B)
edge (A);
\node[c2] (D) at (0.2,0.7) {}
edge (C)
edge (B);
\node[c2] (E) at (1.3,0.5) {}
edge (C)
edge (D);
\end{scope}
\begin{scope}[xshift=2cm,yshift=-0.5cm,rotate around={-40:(0,0)}]
\filldraw[rotate=30,red!10] (0.8,0.1) ellipse (30pt and 25pt);
\node[c3] (a) at (0,0) {};
\node[c3] (b) at (1,1) {}
edge (a);
\node[c3] (c) at (0.7,0.2) {}
edge (b)
edge (a);
\node[c3] (d) at (0.2,0.7) {}
edge (a)
edge (b);
\node[c3] (e) at (1.3,0.5) {}
edge (c)
edge (d);
\node[above of=b] {Community 3};
\end{scope}
\draw (3) -- (A);
\draw (4) -- (D);
\draw (5) -- (a);
\draw (c) -- (E);
\draw (e) -- (B);
\end{tikzpicture}
\end{document}
Ausgabe
Antwort1
Um die Zeichnung wiederverwenden zu können, sollten Sie ein Makro für sie definieren:
Anmerkungen:
- Da ich den Zweck der Zeichnung nicht kenne und nicht weiß, wie sorgfältig Sie Platzierung und Konnektivität wählen möchten, habe ich mich an dem angegebenen Code orientiert.
- Bei sich wiederholenden Aufgaben ist zu beachten, dass jede Aufgabe auf ähnliche Weise betrachtet werden sollte. Beim Platzieren des Knotentexts verwenden Sie beispielsweise zweimal absolute Koordinaten und beim dritten Mal eine relative Platzierung. Ich habe mich für die absolute Position entschieden, aber das ist möglicherweise nicht ideal. Dadurch wurde die Platzierung der dritten Knotenbeschriftung natürlich zu einer Art Ratespiel durch Ausprobieren. Im
Relative Placement of Labels
folgenden Abschnitt finden Sie eine möglicherweise bessere Option. - Die Knoten werden mit
A<color>
, …D<color>
(wobei<color>
der dritte Parameter für ist\MyNodes
) gekennzeichnet, sodass sie systematisch benannt und dann auch außerhalb der Knotenzeichnung beliebig referenziert werden können.
Code: Feste Platzierung der Etiketten
\documentclass[tikz, border=2pt]{standalone}
\begin{document}
\begin{tikzpicture}[scale = 1,node distance = 10mm]
\tikzset{
every node/.append style={circle, thick,
inner sep=0pt, minimum size = 3mm},
every label/.append style={red},
c1/.style={draw=blue!50,fill=blue!20},
c2/.style={draw=green!80,fill=green!40},
c3/.style={draw=red!80,fill=red!40}
}
\newcommand*{\MyNodes}[6]{%
% #1 = style
% #2 = style
% #3 = node name suffix.
% #4 = node to connect to last node
% #5 = label position
% #6 = label text
\filldraw[rotate=30,#1] (0.8,0.1) ellipse (30pt and 25pt);
\node at #5 {#6};
\node[#2] (A#3) at (0,0) {};
\node[#2] (B#3) at (1,1) {}
edge (A#3);
\node[#2] (C#3) at (0.7,0.2) {}
edge (B#3)
edge (A#3);
\node[#2] (D#3) at (0.2,0.7) {}
edge (C#3)
edge (B#3);
\node[#2] (E#3) at (1.3,0.5) {}
edge (#4#3)
edge (D#3);
}%
\MyNodes{blue!10}{c1}{Blue}{B}{(1,1.7)}{Community 1}
\begin{scope}[yshift=-2cm,rotate around={-40:(0,0)}]
\MyNodes{green!10}{c2}{Green}{C}{(1.2,-0.2)}{Community 2}
\end{scope}
\begin{scope}[xshift=2cm,yshift=-0.5cm,rotate around={-40:(0,0)}]
\MyNodes{red!10}{c3}{Red}{C}{(0.5,1.75)}{Community 3}
\end{scope}
\draw (CBlue) -- (AGreen);
\draw (DBlue) -- (DGreen);
\draw (EBlue) -- (ARed);
\draw (CRed) -- (EGreen);
\draw (ERed) -- (BGreen);
\end{tikzpicture}
\end{document}
Sie können die Knotenbeschriftungen auch relativ platzieren, was meiner Meinung nach eine bessere Option ist. Um zu bestimmen, wo die Beschriftungen platziert werden sollen, ist es hilfreich zu wissen, welche Beschriftungen sich wo befinden, und das \Debug
folgende Makro ermöglicht Ihnen, dies zu sehen. Wenn Sie die nachfolgende Zeile im MWE auskommentieren, werden die Knotenbeschriftungen unterdrückt.
Code: Relative Platzierung von Beschriftungen
\documentclass{article}
\usepackage{tikz}
\tikzset{%
every node/.append style={circle, thick,
inner sep=0pt, minimum size = 3mm},
every label/.append style={red},
c1/.style={draw=blue!50,fill=blue!20},
c2/.style={draw=green!80,fill=green!40},
c3/.style={draw=red!80,fill=red!40}
}
\newcommand*{\Debug}[1]{\tiny#1}%
%\renewcommand*{\Debug}[1]{}% Comment this out for debugging
\newcommand*{\MyNodes}[6]{%
% #1 = style
% #2 = style
% #3 = node name sufffix.
% #4 = node to connect to last node
% #5 = label position
% #6 = label text
\filldraw[rotate=30,#1] (0.8,0.1) ellipse (30pt and 25pt);
\node[#2] (A#3) at (0,0) {\Debug{A}};
\node[#2] (B#3) at (1,1) {\Debug{B}}
edge (A#3);
\node[#2] (C#3) at (0.7,0.2) {\Debug{C}}
edge (B#3)
edge (A#3);
\node[#2] (D#3) at (0.2,0.7) {\Debug{D}}
edge (C#3)
edge (B#3);
\node[#2] (E#3) at (1.3,0.5) {\Debug{E}}
edge (#4#3)
edge (D#3);
\node [#5#3] {#6};
}%
\begin{document}
\begin{tikzpicture}[scale = 1,node distance = 10mm, thick]
\MyNodes{blue!10}{c1}{Blue}{B}{above of=D}{Community 1}
\begin{scope}[yshift=-2cm,rotate around={-40:(0,0)}]
\MyNodes{green!10}{c2}{Green}{C}{below of=C}{Community 2}
\end{scope}
\begin{scope}[xshift=2cm,yshift=-0.5cm,rotate around={-40:(0,0)}]
\MyNodes{red!10}{c3}{Red}{C}{above of=B}{Community 3}
\end{scope}
\draw (CBlue) -- (AGreen);
\draw (DBlue) -- (DGreen);
\draw (EBlue) -- (ARed);
\draw (CRed) -- (EGreen);
\draw (ERed) -- (BGreen);
\end{tikzpicture}
\end{document}
Antwort2
Erneuter Optimierungsversuch. Dabei kommen PGF-Schlüssel zum Einsatz.
Haftungsausschluss: Das Ergebnis ist nicht genau dasselbe, da ich den ellipse
Knoten anstelle des ellipse
Pfads verwendet habe (und die Koordinaten ein wenig anpassen musste).
Der Vorteil, den ich hier sah, war die label
Möglichkeit, die „Community“-Beschriftungen hinzuzufügen. Außerdem können Sie darauf für die spätere Verwendung verweisen.
Es gibt einen Befehl:
\drawBlob[<optional arguments](<coordinate>);
Das (<coordinate>)
ist der Ort (0,0)
des lokalen Koordinatensystems.
Da im Bild einige Transformationen stattfinden, bin ich mir nicht ganz sicher, wo die Blobs sind. Beachten Sie nur, dass sich der erste Mini-Blob ( A
) ohne Rotation bei befinden wird (<coordinate>)
.
Sie können die Stile verwenden
every blob picture
,every mini blob
,every blob
, Undevery mini blob edge
um den Inhalt anzupassen. Diese sind ähnlich aufgebaut wie die every node
Styles. Zu jedem every <something>
Style gibt es einen <something>
Style, der sein Element an den entsprechenden every
Style anfügt.
Darüber hinaus gibt es noch drei weitere Schlüssel:
connect mini blobs
,blob name
, Undrotate blob
.
Die rotate blob
Taste dreht das gesamte Bild (den großen Blob und die Mini-Blobs) um die Mitte des großen Blobs.
Der Wert des blob name
Schlüssels wird zur Benennung des großen Blobs (der nach dem Schlüssel benannt ist) und der Mini-Blobs (die dort benannt sind, <value of blob name>-<char>
wo <char>
zwischen A
und steht E
) verwendet.
Wenn blob name
nicht angegeben (z. B. leer, wenn kein Standardname angegeben ist), erhalten die Knoten einen internen Namen (unter dem sie später immer noch aufgrund eines internen Zählers referenziert werden können).
Der Zähler wird nicht wirklich benötigt, wenn die Knoten später nicht referenziert werden …
Schließlich gibt es noch connect mini blobs
. Dieser Schlüssel sollte eine Liste von Mini-Blobs erhalten, die innerhalb des Blobs verbunden werden sollen.
Da Ihr Beispiel darauf hinzuweisen scheint, dass sie immer auf die gleiche Weise verbunden werden, habe ich diesen Stil mit voreingestellt
\tikzset{connect mini blobs={A/B,A/C,B/C,B/D,C/D,C/E,D/E}}
Dies zeigt den Vorteil der Verwendung von PGF-Schlüsseln. Sie können Standardwerte festlegen, Sie können sie mitten im Dokument ändern, Sie können .append
Einstellungen vornehmen und Sie können für jeden neuen Blob unterschiedliche Einstellungen haben.
Sie können auch mini blob <char>
Stile festlegen, um jeden Mini-Blob weiter anzupassen.
Und es gibt every minin blob edge
, für die Linie die nach innen gezeichneten Kanten zwischen den Mini-Blobs.
VerbesserungenoderVielleicht die fit
Bibliothek?
Fällt Ihnen auf, dass beim Zeichnen der Mini-Blobs ähnliche Linien entstehen?
Eine Verbesserung wäre, auch die Anzahl und den Standort dieser Mini-Blobs anzupassen. Ein paar Tasten und eins \foreach
würden genügen.
Die Ellipse kann dann – mit Hilfe der Bibliothek – mit (z. B. ) background
gezeichnet werden , allerdings muss die Rotation dieser Ellipse manuell definiert werden und die tatsächliche Größe hängt von ab . Auch hier finden zu viele Transformationen statt.fit
fit=(\qrr@blob@name-A)(\qrr@blob@name-B)…
rotate blob
Code
\documentclass[tikz]{standalone}
\usetikzlibrary{shapes.geometric}
\makeatletter
%% Setup
\tikzset{
connect mini blobs/.store in=\qrr@blob@connections,
connect mini blobs=,
blob name/.store in=\qrr@blob@name,
blob name=,
rotate blob/.store in=\qrr@blob@rotate,
rotate blob=0,
% short-cut styles
blob picture/.style={every blob picture/.append style={#1}},
mini blob/.style={every mini blob/.append style={#1}},
blob/.style={every blob/.append style={#1}},
mini blob edge/.style={every mini blob edge/.append style=#1},
% a few defaults
every blob picture/.style={},
every mini blob/.style={shape=circle, thick, draw, minimum size=3mm},
every blob/.style={shape=ellipse, draw, fill, inner sep=0pt, minimum width=60pt, minimum height=50pt},
every mini blob edge/.style={thick},
}
\newcount\c@qrr@blob@count
\newcommand*{\drawBlob}[1][]{\begingroup\tikzset{#1}\draw@blob}
\def\draw@blob(#1){%
\ifx\qrr@blob@name\pgfutil@empty
\edef\qrr@blob@name{qrr@mini-blob@\the\c@qrr@blob@count}%
\fi
\scope[absolute, every blob picture/.try]
\node[shift={(#1)}, rotate=30+\qrr@blob@rotate, every blob/.try] (\qrr@blob@name) at (0.6,0.5) {};
\node[every mini blob/.try, mini blob A/.try, shift={(#1)}, ] (\qrr@blob@name-A) at ([rotate around={\qrr@blob@rotate:(0.6,0.5)}] 0,0) {};
\node[every mini blob/.try, mini blob B/.try, shift={(#1)}, ] (\qrr@blob@name-B) at ([rotate around={\qrr@blob@rotate:(0.6,0.5)}] 1,1) {};
\node[every mini blob/.try, mini blob C/.try, shift={(#1)}, ] (\qrr@blob@name-C) at ([rotate around={\qrr@blob@rotate:(0.6,0.5)}] 0.7,0.2) {};
\node[every mini blob/.try, mini blob D/.try, shift={(#1)}, ] (\qrr@blob@name-D) at ([rotate around={\qrr@blob@rotate:(0.6,0.5)}] 0.2,0.7) {};
\node[every mini blob/.try, mini blob E/.try, shift={(#1)}, ] (\qrr@blob@name-E) at ([rotate around={\qrr@blob@rotate:(0.6,0.5)}] 1.3,0.5) {};
\foreach \qrr@blob@connection@start/\qrr@blob@connection@target in \qrr@blob@connections {
\path[every mini blob edge/.try] (\qrr@blob@name-\qrr@blob@connection@start) edge (\qrr@blob@name-\qrr@blob@connection@target);}
\endscope
\endgroup
\advance\c@qrr@blob@count\@ne
}
\makeatother
%%% Standard connections
\tikzset{connect mini blobs={A/B,A/C,B/C,B/D,C/D,C/E,D/E}} % that's always the same
%%% Custom styles
\tikzset{
c1/.style={draw=blue!50,fill=blue!20},
c2/.style={draw=green!80,fill=green!40},
c3/.style={draw=red!80,fill=red!40}
}
\begin{document}
\begin{tikzpicture}
\drawBlob[
mini blob=c1,
blob={color=blue!10, label=above:Community 1},
blob name=Comm1
](0,0)
\drawBlob[
mini blob=c2,
blob={color=green!10, label=below:Community 2},
blob name=Comm2,
rotate blob=-40
](0,-3)
\drawBlob[
mini blob=c3,
blob={color=red!10, label=above:Community 3},
blob name=Comm3,
rotate blob=-40
](2.5,-.5)
\foreach \start/\target in {1-C/2-A,1-D/2-D,1-E/3-A,3-C/2-E,3-E/2-B} \draw[every mini blob edge] (Comm\start) -- (Comm\target);
\end{tikzpicture}
\end{document}