
Eu tenho o seguinte trecho de código TikZ e queria saber se ele pode ser otimizado. (Na verdade, tenho certeza de que pode ser!)
O principal problema é este: quando giro o primeiro lote de nós cercados pela elipse para criar o segundo lote, a elipse fica fora do lugar. (Não está onde eu esperava. Não tenho certeza de qual ponto está fixo na rotação.) Tenho que ajustá-lo às cegas para movê-lo para o local desejado.
O mesmo vale para os rótulos “Comunidade 2” e “Comunidade 3”. As coordenadas giradas não parecem corresponder ao que eu esperava e tenho que ajustá-las cegamente com sucesso limitado.
Em uma observação não relacionada: também experimentei loops for, mas como quero que as bordas de cada comunidade sejam um pouco diferentes, parece que copiar e colar direto é mais fácil?
Outras otimizações também são bem-vindas.
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}
Saída
Responder1
Você deve definir uma macro para o desenho para poder reutilizá-lo:
Notas:
- Como não sei a intenção do desenho e com que cuidado você deseja escolher o posicionamento e a conectividade, baseei-o no código fornecido.
- Uma coisa a ter em mente ao fazer coisas repetidas é que cada tarefa deve ser pensada de maneira semelhante. Por exemplo, ao posicionar o texto do nó, você usa coordenadas absolutas duas vezes e, na terceira vez, usa um posicionamento relativo. Decidi escolher a posição absoluta, mas isso pode não ser o ideal. É claro que isso tornou a colocação do rótulo do terceiro nó uma espécie de suposição por tentativa e erro. Veja
Relative Placement of Labels
a seção abaixo que pode ser uma opção melhor. - Os nós são rotulados como
A<color>
, ...D<color>
(onde<color>
é o terceiro parâmetro para\MyNodes
) para que possam ser nomeados sistematicamente e depois referenciados conforme desejado fora do desenho dos nós.
Código: Colocação Fixa 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}
Você também pode colocar os rótulos dos nós de maneira relativa, o que considero uma opção melhor. Para determinar onde colocar os rótulos, é útil saber quais rótulos estão onde, e a \Debug
macro abaixo permite que você veja isso. Se você remover o comentário da linha subsequente no MWE, os rótulos dos nós serão suprimidos.
Código: Colocação 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}
Responder2
Outra tentativa de otimização. Isso usa chaves PGF.
Isenção de responsabilidade: o resultado não é exatamente o mesmo, pois usei o ellipse
nó em vez do ellipse
caminho (e tive que ajustar um pouco as coordenadas).
A vantagem que vi aqui foi a utilização da label
opção de adicionar os rótulos “Comunidade”. Além disso, você pode consultá-lo para uso posterior.
Existe um comando:
\drawBlob[<optional arguments](<coordinate>);
É (<coordinate>)
onde (0,0)
está o sistema de coordenadas local.
Como são algumas transformações acontecendo na imagem, não tenho muita certeza de onde estão as bolhas. Observe apenas que, sem rotação, o primeiro mini blob ( A
) estará em (<coordinate>)
.
Você pode usar os estilos
every blob picture
,every mini blob
,every blob
, eevery mini blob edge
para personalizar o conteúdo. Existem configurações semelhantes ao every node
estilo. Para cada every <something>
estilo existe um <something>
estilo que anexa seu elemento ao every
estilo correspondente.
Além disso, existem mais três chaves:
connect mini blobs
,blob name
, erotate blob
.
A rotate blob
tecla gira a imagem inteira (a bolha grande e as mini bolhas) em torno do centro da bolha grande.
O valor da blob name
chave será usado para nomear o blob grande (que recebe o nome da chave) e os mini blobs (que são nomeados <value of blob name>-<char>
onde <char>
está entre A
e E
).
Se blob name
não for fornecido (por exemplo, vazio, se um padrão não for especificado), os nós receberão um nome interno (pelo qual ainda poderão ser referenciados posteriormente devido a um contador interno).
O contador não é realmente necessário quando os nós não serão referenciados posteriormente…
Finalmente, existe connect mini blobs
. Essa chave deve receber uma lista de miniblobs que devem ser conectados dentro do blob.
Como seu exemplo parece sugerir que eles estão sempre conectados da mesma maneira, eu pré-defini esse estilo com
\tikzset{connect mini blobs={A/B,A/C,B/C,B/D,C/D,C/E,D/E}}
Isto traz à tona a vantagem de usar chaves PGF. Você pode definir valores padrão, alterá-los no meio do documento, definir .append
configurações e ter configurações diferentes para cada novo blob.
Você também pode definir mini blob <char>
estilos para personalizar ainda mais cada mini blob.
E há every minin blob edge
, para a linha das bordas desenhadas internamente entre as mini bolhas.
MelhoriasouTalvez a fit
biblioteca?
Observe como existem linhas semelhantes ao desenhar as mini bolhas?
Uma melhoria seria personalizar também o número e a localização desses mini blobs. Algumas chaves e um \foreach
bastariam.
A elipse pode - com a ajuda da background
biblioteca - ser desenhada com fit
(por exemplo fit=(\qrr@blob@name-A)(\qrr@blob@name-B)…
), embora a rotação desta elipse tenha que ser definida manualmente e o tamanho real dependa de rotate blob
. Novamente, muitas transformações acontecendo.
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}