
Tengo el siguiente código TikZ y me preguntaba si se puede optimizar. (¡Estoy seguro de que puede serlo!)
El problema principal es este: cuando giro el primer lote de nodos rodeados por la elipse para crear el segundo lote, la elipse está fuera de lugar. (No está donde esperaba que estuviera. No estoy seguro de qué punto está fijo en la rotación). Tengo que ajustarlo a ciegas para moverlo al lugar deseado.
Lo mismo ocurre con las etiquetas "Comunidad 2" y "Comunidad 3". Las coordenadas rotadas no parecen coincidir con lo que esperaba y tengo que ajustarlas a ciegas con un éxito limitado.
En una nota no relacionada: también he experimentado con bucles for, pero como quiero que los bordes en cada comunidad sean ligeramente diferentes, ¿parece que copiar y pegar directamente es más fácil?
Otras optimizaciones también son bienvenidas.
código
\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}
Producción
Respuesta1
Debes definir una macro para el dibujo para poder reutilizarlo:
Notas:
- Como no sé la intención del dibujo y con qué cuidado desea elegir la ubicación y la conectividad, lo basé en el código proporcionado.
- Una cosa a tener en cuenta al hacer cosas repetidas es que cada tarea debe considerarse de manera similar. Por ejemplo, al colocar el texto del nodo, utiliza coordenadas absolutas dos veces y la tercera vez utiliza una ubicación relativa. Decidí elegir la posición absoluta, pero puede que no sea la ideal. Por supuesto, esto hizo que la ubicación de la etiqueta del tercer nodo fuera algo así como una suposición por prueba y error. Consulte
Relative Placement of Labels
la sección a continuación cuál puede ser una mejor opción. - Los nodos están etiquetados como
A<color>
,...D<color>
(donde<color>
está el tercer parámetro para\MyNodes
) para que se puedan nombrar sistemáticamente y luego hacer referencia a ellos como se desee fuera del dibujo de los nodos.
Código: Colocación fija de etiquetas
\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}
También puedes colocar las etiquetas de los nodos de forma relativa, lo cual creo que es una mejor opción. Para determinar dónde colocar las etiquetas, es útil saber qué etiquetas están y dónde, y la \Debug
siguiente macro le permite verlo. Si descomenta la línea siguiente en el MWE, se suprimirán las etiquetas de los nodos.
Código: Colocación relativa de etiquetas
\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}
Respuesta2
Otro intento de optimización. Esto utiliza claves PGF.
Descargo de responsabilidad: el resultado no es exactamente el mismo, ya que usé el ellipse
nodo en lugar de la ellipse
ruta (y tuve que ajustar un poco las coordenadas).
La ventaja que vi aquí fue el uso de la label
opción para agregar las etiquetas "Comunidad". Además, puede consultarlo para su uso posterior.
Hay un comando:
\drawBlob[<optional arguments](<coordinate>);
Es (<coordinate>)
donde (0,0)
está el sistema de coordenadas local.
Como hay algunas transformaciones en la imagen, no estoy del todo seguro de dónde están las manchas. Solo tenga en cuenta que, sin rotación, el primer mini blob ( A
) estará en (<coordinate>)
.
Puedes usar los estilos.
every blob picture
,every mini blob
,every blob
, yevery mini blob edge
para personalizar el contenido. Hay configuraciones similares al every node
estilo. Para cada every <something>
estilo existe un <something>
estilo que añade su elemento al every
estilo correspondiente.
Además, hay tres claves más:
connect mini blobs
,blob name
, yrotate blob
.
La rotate blob
tecla gira la imagen completa (la gran masa y las minimanchas) alrededor del centro de la gran masa.
El valor de la blob name
clave se utilizará para nombrar el blob grande (que lleva el nombre de la clave) y los mini blobs (que se nombran entre <value of blob name>-<char>
y <char>
) .A
E
Si blob name
no se proporciona (por ejemplo, vacío, si no se especifica uno predeterminado), los nodos obtendrán un nombre interno (por el cual aún se podrá hacer referencia a ellos más adelante debido a un contador interno).
El contador no es realmente necesario cuando no se hará referencia a los nodos más adelante...
Finalmente, lo hay connect mini blobs
. A esta clave se le debe proporcionar una lista de miniblobs que deben conectarse dentro del blob.
Como su ejemplo parece insinuar que siempre están conectados de la misma manera, preestablecí este estilo con
\tikzset{connect mini blobs={A/B,A/C,B/C,B/D,C/D,C/E,D/E}}
Esto resalta la ventaja de utilizar claves PGF. Puede establecer valores predeterminados, puede cambiarlos a mitad del documento, puede .append
configurar y puede tener configuraciones diferentes para cada nuevo blob.
También puede establecer mini blob <char>
estilos para personalizar aún más cada mini blob.
Y está every minin blob edge
, para la línea de bordes dibujados internamente entre las mini manchas.
Mejoraso¿Quizás la fit
biblioteca?
¿Observas que hay líneas similares al dibujar las mini manchas?
Una mejora sería personalizar también el número y la ubicación de estos miniblobs. Unas cuantas llaves y un \foreach
sería suficiente.
La elipse que se puede background
dibujar (con la ayuda de la biblioteca) fit
(p. ej. fit=(\qrr@blob@name-A)(\qrr@blob@name-B)…
), aunque la rotación de esta elipse tendrá que definirse manualmente y el tamaño real dependerá de rotate blob
. Una vez más, se están produciendo demasiadas transformaciones.
Código
\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}