
Existe algum pacote para desenhar bons gráficos RDF, como o abaixo (retirado delá)?
Esse gráfico (com o mesmo estilo) pode ser produzido no TikZ?
Responder1
À primeira vista eu começaria a definir o estilo capaz de representar os vértices; precisamos basicamente de:
- uma elipse;
- algumas definições de tamanho;
- desenhar a borda mais espessa e definir a cor de preenchimento mais brilhante em relação à borda;
- deixando o texto na cor branca;
- talvez reduza um pouco o tamanho da fonte do texto.
A definição de estilo no TikZ pode ser feita via \tikzset
:
\tikzset{vertex style/.style={
draw=#1,
thick,
fill=#1!70,
text=white,
ellipse,
minimum width=2cm,
minimum height=0.75cm,
font=\small,
outer sep=3pt, % the usage of this option will be clear later on
},
}
Observe duas coisas: esse estilo recebe um argumento, a cor e deixa a cor de preenchimento mais brilhante misturando a cor com o branco. Em segundo lugar, a ellipse
forma requer a biblioteca:
\usetikzlibrary{shapes.geometric}
Vamos agora criar o primeiro vértice. Eu começaria com o "Righteous Kill", de onde partem a maioria das conexões.
\documentclass[dvipsnames,png,border=10pt,tikz]{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric} % required for the ellipse shape
\tikzset{vertex style/.style={
draw=#1,
thick,
fill=#1!70,
text=white,
ellipse,
minimum width=2cm,
minimum height=0.75cm,
font=\small,
outer sep=3pt,
},
}
\begin{document}
\begin{tikzpicture}
\node[vertex style=Turquoise] (Rk) {Righteous Kill};
\end{tikzpicture}
\end{document}
Cuidado com a opção dvipsnames
: foi necessário configurá-la nas opções da classe para evitar um possível option clash
erro, pois o TikZ carrega sozinho xcolor
.
O nó utiliza o estilo definido acima definindo sua cor (definição no xcolor
manual), seu nome (Rk)
e seu texto {Righteous Kill}
.
O resultado:
De agora em diante, não exibirei em nenhum momento o preâmbulo, mas apenas o código da imagem.
O segundo passo é localizar os outros nós. Pode-se explorar muitas possibilidades (usando GraphViz, usando o módulo orientado a objetos do PGF e construir alguma classe customizada - veja:Desenhando relacionamentos entre elementos de um banco de dados): aqui eu uso a positioning
biblioteca do TikZ. Cada vértice, portanto, será localizado a partir da posição dos demais vértices, referindo-se aos seus nomes.
Aviso: como cada vértice precisa estar conectado a outro, a sintaxe
\node[options] (a) {text a} ... edge[options] node[options]{text conn} (b);
conectará os vértices a
e b
definirá um rótulo para a conexão text conn
. Extremamente útil neste caso. Na verdade, vamos começar a adicionar outro nó:
\begin{tikzpicture}[node distance=2.75cm,>=stealth']
\node[vertex style=Turquoise] (Rk) {Righteous Kill};
\node[vertex style=BurntOrange, above of=Rk,xshift=2em] (BD) {Bryan Dennehy}
edge [<-,cyan!60!blue] node[text style,above]{starring} (Rk);
\end{tikzpicture}
As opções node distance=2.75cm,>=stealth'
referem-se à distância básica do vértice e ao tipo de ponta da seta utilizada para a conexão. Devido à ponta da seta selecionada, a biblioteca arrows
deve ser carregada.
Observe que o texto de conexão requer um estilo: text style
. Sua definição é:
\tikzset{
text style/.style={
sloped, % the text will be parallel to the connection
text=black,
font=\footnotesize,
above
}
}
A localização do novo nó é feita através das opções above of=Rk,xshift=2em
: a primeira define a posição em relação ao nome do nó anterior que criamos antes, a segunda desloca um pouco para a direita esta posição.
Resultado:
Uma vez compreendido este mecanismo, é possível localizar todos os outros nós:
\begin{tikzpicture}[node distance=2.75cm,>=stealth']
\node[vertex style=Turquoise] (Rk) {Righteous Kill};
\node[vertex style=BurntOrange, above of=Rk,xshift=2em] (BD) {Bryan Dennehy}
edge [<-,cyan!60!blue] node[text style]{starring} (Rk);
\node[vertex style=BurntOrange, right=1.5cm of Rk,yshift=4ex] (AP) {Al Pacino}
edge [<-,cyan!60!blue] node[text style]{starring} (Rk);
\node[vertex style=red, below right of=Rk,xshift=2em] (JA) {John Avnet}
edge [<-,cyan!60!blue] node[text style]{director} (Rk);
\node[vertex style=BurntOrange, right=1.5cm of Rk,yshift=-4ex] (RN) {Robert De Niro}
edge [<-,cyan!60!blue] node[text style]{starring} (Rk);
\node[vertex style=MidnightBlue, above right of=Rk,xshift=2em] (Dr) {Drama}
edge [<-,cyan!60!blue] node[text style]{genre} (Rk);
\node[vertex style=Maroon, below of=Rk,xshift=-2em] (Skf) {Serial Killer Films}
edge [<-,cyan!60!blue] node[text style]{subject} (Rk);
\node[vertex style=Maroon, below right of=Skf] (Cf) {Crime Films}
edge [<-,cyan!60!blue] node[text style]{broader} (Skf);
\end{tikzpicture}
Terminada esta tarefa, é possível começar a adicionar o fundo "líquido" ao redor de alguns vértices.
Para colocar algo no fundo, a biblioteca backgrounds
é útil, assim como a hobby
biblioteca de Andrew Stacey para desenhar a curva suave. Além disso, muitas vezes são necessários alguns cálculos, portanto a biblioteca também calc
deve ser carregada.
A definição do caminho deve ser feita da seguinte forma: partindo do norte do nó (Rk)
, circunavega-se todas as âncoras possíveis dos nós interessados a serem destacados. Existem algumas ferramentas automáticas, vejaRealização de caminho de hobby na abordagem de casco convexo, mas eles não podem ser precisos e ajustar as coisas como alguns trabalhos manuais podem fazer. E, neste caso, permite obter um melhor resultado.
\begin{pgfonlayer}{background}
\draw[Maroon,fill=Maroon,dashed,fill opacity=0.1](Rk.north)
to[closed,curve through={(Rk.north west).. (Rk.west) .. (Rk.south west)
..($(Rk.south west)!0.5!(Skf.north)$) .. (Skf.north west).. (Skf.west)
.. (Skf.south west) .. ($(Skf.south)!0.75!(Cf.west)$) .. (Cf.west)
.. (Cf.south west) .. (Cf.south) .. (Cf.south east) .. (Cf.east)
.. ($(Cf.north east)!0.65!(Skf.south east)$) .. (Skf.east)
.. (Skf.north east).. ($(Skf.north)!0.35!(Rk.south east)$)
.. (Rk.south east) .. (Rk.east)..(Rk.north east)}](Rk.north);
\end{pgfonlayer}
Mais ou menos esse é o código... mas esse é o resultado:
A opção misteriosa outer sep=3pt
permite não deixar o “fundo líquido” muito próximo do formato da borda. E agora é tudo!
O código completo para referência:
\documentclass[dvipsnames,png,border=10pt,tikz]{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric} % required for the ellipse shape
\usetikzlibrary{arrows, backgrounds, calc, hobby, positioning}
% this avoides some problem with the hobby implementation
% egreg's code from:
% http://www.guitex.org/home/it/forum/5-tex-e-latex/83195-la-libreria-hobby-tikz-non-funziona-piu#83203
\ExplSyntaxOn
\cs_if_exist:NF \prg_stepwise_function:nnnN { \cs_gset_eq:NN \prg_stepwise_function:nnnN \int_step_function:nnnN }
\cs_if_exist:NF \prg_stepwise_inline:nnnn { \cs_gset_eq:NN \prg_stepwise_inline:nnnn \int_step_inline:nnnn }
\ExplSyntaxOff
\tikzset{vertex style/.style={
draw=#1,
thick,
fill=#1!70,
text=white,
ellipse,
minimum width=2cm,
minimum height=0.75cm,
font=\small,
outer sep=3pt,
},
text style/.style={
sloped,
text=black,
font=\footnotesize,
above
}
}
\begin{document}
\begin{tikzpicture}[node distance=2.75cm,>=stealth']
\node[vertex style=Turquoise] (Rk) {Righteous Kill};
\node[vertex style=BurntOrange, above of=Rk,xshift=2em] (BD) {Bryan Dennehy}
edge [<-,cyan!60!blue] node[text style]{starring} (Rk);
\node[vertex style=BurntOrange, right=1.5cm of Rk,yshift=4ex] (AP) {Al Pacino}
edge [<-,cyan!60!blue] node[text style]{starring} (Rk);
\node[vertex style=red, below right of=Rk,xshift=2em] (JA) {John Avnet}
edge [<-,cyan!60!blue] node[text style]{director} (Rk);
\node[vertex style=BurntOrange, right=1.5cm of Rk,yshift=-4ex] (RN) {Robert De Niro}
edge [<-,cyan!60!blue] node[text style]{starring} (Rk);
\node[vertex style=MidnightBlue, above right of=Rk,xshift=2em] (Dr) {Drama}
edge [<-,cyan!60!blue] node[text style]{genre} (Rk);
\node[vertex style=Maroon, below of=Rk,xshift=-2em] (Skf) {Serial Killer Films}
edge [<-,cyan!60!blue] node[text style]{subject} (Rk);
\node[vertex style=Maroon, below right of=Skf] (Cf) {Crime Films}
edge [<-,cyan!60!blue] node[text style]{broader} (Skf);
\begin{pgfonlayer}{background}
\draw[Maroon,fill=Maroon,dashed,fill opacity=0.1](Rk.north)
to[closed,curve through={(Rk.north west).. (Rk.west) .. (Rk.south west)
..($(Rk.south west)!0.5!(Skf.north)$) .. (Skf.north west).. (Skf.west)
.. (Skf.south west) .. ($(Skf.south)!0.75!(Cf.west)$) .. (Cf.west)
.. (Cf.south west) .. (Cf.south) .. (Cf.south east) .. (Cf.east)
.. ($(Cf.north east)!0.65!(Skf.south east)$) .. (Skf.east)
.. (Skf.north east).. ($(Skf.north)!0.35!(Rk.south east)$)
.. (Rk.south east) .. (Rk.east)..(Rk.north east)}](Rk.north);
\end{pgfonlayer}
\end{tikzpicture}
\end{document}