Problema

Problema

Problema

En TikZ, se puede controlar la dirección de crecimiento de una rama (y sus subramas) usando la grow=<direction>tecla. En forest, sin embargo, la growclave sólo controla la dirección creciente de lasubramaspero no su rama matriz.

¿Cómo hago para que las ramas que están al mismo nivel en un forestárbol crezcan en diferentes direcciones?En el siguiente MWE, por ejemplo, ¿cómo puedo child 2extenderme horizontalmente desde rootel árbol TikZ?

MWE

\documentclass{article}
\usepackage{tikz,forest}

\begin{document}
\texttt{grow} used in a Ti\textit{k}Z tree

\begin{tikzpicture}
  \node{root}
    child{node{child 1}}
    child[grow=east]{node{child 2}
      child child child
    }
  ;
\end{tikzpicture}

\vskip20pt
\texttt{grow} used in a Forest tree

\begin{forest}
  [root
    [child 1]
    [child 2,grow=east
      [][][]
    ]
  ]
\end{forest}
\end{document}

ingrese la descripción de la imagen aquí

Respuesta1

El efecto deseado se puede lograr moviendo el subárbol del nodo child 2manualmente. Puedo ver dos formas de hacer esto.

  1. Cambie la posición relativa ( ly s) de child 2justo antes del escenario compute xy. Tenga en cuenta que child 2's ly sson coordenadas en el rootsistema de coordenadas ls de ' (consulte la documentación para conocer las opciones ly s). Dado que estas coordenadas son relativas al padre, solo es necesario cambiarlas para la raíz del subárbol child 2.

  2. Cambiar la posición absoluta ( xy y) detodos los nodos en child 2el subárbolJusto antes del escenario draw tree.

    Una nota. En el ejemplo, yse ajusta para que child 2esté alineado verticalmente con root: dado que esto se logra calculando la diferencia entre root's y child 2's y, el nodo child 2debe moverse después de sus descendientes.

Tenga en cuenta que en ambos enfoques, forestprimero coloca a los hijos de la raíz en la dirección de crecimiento predeterminada de -90 grados, lo que en principio puede influir tanto en la posición (tenga en cuenta que child 1está a la izquierda de la raíz) como en la estructura interna de los subárboles.

\documentclass{article}
\usepackage{forest}

\begin{document}

% the ls way
\begin{forest}
  [root
    [child 1
      [][][]
    ]
    [child 2, for tree={grow=0},
      before computing xy={l=0,s=2cm}
      [][][]
    ]
  ]
\end{forest}

% the xy way
\begin{forest}
  [root
    [child 1
      [][][]
    ]
    [child 2, for tree={grow=0},
      before drawing tree={for descendants=
        {x+=1cm, y+=y("!r")-y("!r2")},
        x+=1cm, y+=y("!r")-y("!r2")
      }
      [][][]
    ]
  ]
\end{forest}

\end{document}

Para ser honesto, ninguno de los dos enfoques me parece elegante. Lo primero que pensé fue integrar dos forestentornos, uno para cada subárbol, en un tikzpictureentorno. Dado que forestfunciona escupiendo tikzcódigo, razoné que debería ser posible posicionar los nodos raíz manualmente usando tikzlos mecanismos de ( at,, right ofetc.). (Tenga en cuenta que begin drawy end drawdebe vaciarse para que esto tenga alguna posibilidad de éxito). Sin embargo, el resultado no fue el esperado... Investigaré los motivos e intentaré solucionar el problema en alguna versión futura de forest.

Respuesta2

Esta es una vieja pregunta, pero como esta funcionalidad no está integrada forest, pensé en ofrecer una solución general.

multiple directionsSe define una nueva opción en un archivo \forestset. La idea básica es que para cada dirección en la que desee que crezca un subárbol, se crea un nodo raíz duplicado y se coloca en la ubicación del nodo raíz real. Entonces cada subárbol puede crecer en su propia dirección ya que técnicamente tiene su propio padre.

Lo mismo \forestsetdefine grow subtreey grow' subtreecuáles requieren una dirección (ángulo o dirección de la brújula). Estos siguen las mismas reglas que grow=y grow'=, es decir, que grow' subtreeinvierten el orden de los nodos en el subárbol. Estos no son nada especiales: grow subtree=es solo una sintaxis alternativa parafor tree={grow=}

El único cambio de formato con respecto a la sintaxis del bosque estándar es que se debe crear un nodo vacío para cada dirección. Aquí hay un ejemplo:

ingrese la descripción de la imagen aquí

El código de este árbol es:

\begin{forest}
    multiple directions
    [root 
      [ 
        [child 1 [a][b]]
      ]
      [, grow subtree=150
        [child 2 [c][d][e]]
      ]
      [, grow' subtree=30
        [child 3 [f][g]]
      ]
    ]
\end{forest}

La opción multiple directionstambién actúa como for treey acepta opciones como se ve en el siguiente ejemplo.

Nota: forked edgerequiere \useforestlibrary{edges}.

ingrese la descripción de la imagen aquí

El código es:

\begin{forest}
    multiple directions={minimum height=4ex, anchor=center, forked edge}
    [R 
      [, grow' subtree=east
        [1 [a][b]]
        [2 [c][d]]
        [3 [e][f]]]
      [, grow subtree=west
        [4 [g][h]]
        [5 [i][j]]
        [6 [k][l]]
      ]
    ]
\end{forest}

Un ejemplo adicional con los nodos dibujados:

ingrese la descripción de la imagen aquí

\begin{forest}
    multiple directions={minimum width=2.5em, anchor=center, circle, draw}
    [c
      [, grow' subtree=north
        [a[a1][a2]]
        [b[b1][b2]]]
      [ 
        [d[d1][d2]]
        [e[e1][e2]]]
    ]
\end{forest}

Tenga en cuenta que el nodo raíz original es un phantom, por lo que si desea cambiar la apariencia del nodo por nivel, debe aumentar el nivel en 1. Por lo tanto, el nodo raíz (visible) (que en realidad es una copia) está en el nivel 1 y sus hijos están en el nivel 2. Por ejemplo:

ingrese la descripción de la imagen aquí

\begin{forest}
    multiple directions={
        text width=20mm,
        if level=1{fill=gray!80}{fill=gray!10},
        if level=2{fill=gray!40}{},
        forked edge,
        s sep=5mm, l sep=5mm,
        fork sep=2.5mm
    }
    [Root
      [, grow subtree=west
        [West of root[Far west]]
      ]
      [
        [A[B]]
        [C[D[E]]]
        [F[G]]
      ]
      [, grow subtree=east
        [East of root[Far east]]
      ]
    ]
\end{forest}

También es posible utilizar multiple directionsen un subárbol:

ingrese la descripción de la imagen aquí

\begin{forest}
    multiple directions={anchor=center}, forked edges
    [0
      [, grow subtree=west
        [1[1a][1b]][2[2a][2b]]]
      [, grow' subtree=east
        [3[3a][3b]][4[4a][4b, multiple directions, phantom=false
            [, grow' subtree=east[x[x1][x2]]]
            [, grow subtree=south[y[y1][y2]]]
        ]]]
    ]
\end{forest}

Tenga en cuenta que debido a la forma en que multiple directionsse oculta el nodo raíz, es necesario configurarlo phantom=falsepara este uso.

Aquí está el código completo incluyendo algunos de los ejemplos:

\documentclass{article}

\usepackage{forest}
\useforestlibrary{edges}

\forestset{multiple directions/.style={for tree={#1}, phantom, for relative level=1{no edge, delay={!c.content/.pgfmath=content("!u")}, before computing xy={l=0,s=0}}},
    multiple directions/.default={},
    grow subtree/.style={for tree={grow=#1}}, 
    grow' subtree/.style={for tree={grow'=#1}}}

\begin{document}

\begin{forest}
    multiple directions
    [root 
      [ 
        [child 1 [a][b]]
      ]
      [, grow subtree=150
        [child 2 [c][d][e]]
      ]
      [, grow' subtree=30
        [child 3 [f][g]]
      ]
    ]
\end{forest}

\vspace{1cm}
\begin{forest}
    multiple directions={minimum height=4ex, anchor=center, forked edge}
    [R 
      [, grow' subtree=east
        [1 [a][b]]
        [2 [c][d]]
        [3 [e][f]]]
      [, grow subtree=west
        [4 [g][h]]
        [5 [i][j]]
        [6 [k][l]]
      ]
    ]
\end{forest}

\vspace{1cm}
\begin{forest}
    multiple directions={minimum width=2.5em, anchor=center, circle, draw}
    [c
      [, grow' subtree=north
        [a[a1][a2]]
        [b[b1][b2]]]
      [ 
        [d[d1][d2]]
        [e[e1][e2]]]
    ]
\end{forest}

\vspace{1cm}
\begin{forest}
    multiple directions={anchor=center}, forked edges
    [0
      [, grow subtree=west
        [1[1a][1b]][2[2a][2b]]]
      [, grow' subtree=east
        [3[3a][3b]][4[4a][4b, multiple directions, phantom=false
            [, grow' subtree=east[x[x1][x2]]]
            [, grow subtree=south[y[y1][y2]]]
        ]]]
    ]
\end{forest}

\end{document}

Respuesta3

Ninguna solución a este problema puede ser perfectamente general. Automatizar el estilo no es necesariamente mejor (o peor) queLa excelente estructuración manual de los árboles de Sandy G.. Esta respuesta pretende ser más automática, un poco más robusta y evitar problemas menores de formato, pero no hay garantía de que no se coma el chocolate ni le robe el calcetín.

Advertencia emptor


Esta es una modificación deExcelente respuesta de Sandy G.. La idea fundamental es la misma, con los siguientes cambios.

  1. El estilo es más automatizado.
  2. Evita componer múltiples copias del mismo contenido de nodo, lo cual es responsable del efecto de negrita falsa en los nodos que generan subárboles en múltiples direcciones. (Pero hay formas mucho más fáciles si esta es su única preocupación).
  3. Intenta ser potencialmente un poco más robusto al integrar uno de los cambios enLa respuesta aún más excelente de Sašo Živanović. (Esto no significa que funcionará con folderestilo; ni siquiera lo heintentó¡él!)

El resultado debe ser el mismo que si se utilizara la respuesta de Sandy G (peso de fuente aparente del módulo). Sólo difiere la especificación de los árboles.

Producción sin negrita falsa en puntos de crecimiento divergentes

Sólo dos claves son realmente interesantes para especificar los árboles.

subtree grow=<growth direction>
subtree grow'=<growth direction>

Estos pretenden ser precisamente análogos a grow subtreey grow subtree'.

La principal diferencia es que esto es todo lo que necesitamos hacer. No es necesario insertar nodos adicionales ni especificar ningún estilo para el árbol en su conjunto. subtree growy subtree grow'active el estilo requerido, que inserta los nodos adicionales necesarios.

Tomando los ejemplos de Sandy G con fines de demostración, el primero se puede especificar simplemente como

\begin{forest}
  [root
    [child 1 
      [a][b]
    ]
    [child 2, subtree grow=150
      [c][d][e]
    ]
    [child 3, subtree grow'=30
      [f][g]
    ]
  ]
\end{forest}

Por supuesto, esta simplicidad tiene un inconveniente. En algunos árboles, tenemos que escribir con mayor precisión porque no tenemos un nodo falso adicional para establecer la dirección de crecimiento de un subárbol completo. En cambio, debemos especificar la dirección de crecimiento para cada niño que no debería crecer en la dirección predeterminada determinada por los padres. Por lo tanto, el segundo árbol de Sandy G requiereseisusos de subtree grow/ subtree grow', mientras que solo requeríadosde grow subtree/ grow subtree'.

[Si el ejemplo anterior fueron los columpios, supongo que ya estamos en las rotondas.]

\begin{forest}
  for tree={minimum height=4ex, anchor=center},
  forked edges,
  [R 
    [1, subtree grow'=east 
      [a][b]
    ]
    [2, subtree grow'=east 
      [c][d]
    ]
    [3, subtree grow'=east 
      [e][f]
    ]
    [4, subtree grow=west 
      [g][h]
    ]
    [5, subtree grow=west 
      [i][j]
    ]
    [6, subtree grow=west 
      [k][l]
    ]
  ]
\end{forest}

Para el tercer ejemplo, necesitamos dos usos de subtree grow', pero como no tenemos que insertar nodos adicionales ni agregar nada al preámbulo, esto sigue siendo un poco más conciso.

\begin{forest}
  for tree={minimum width=2.5em, anchor=center, circle, draw},
  [c
    [a, subtree grow'=north
      [a1][a2]
    ]
    [b, subtree grow'=north
      [b1][b2]
    ]
    [d
      [d1][d2]
    ]
    [e
      [e1][e2]
    ]
  ]
\end{forest}

De manera similar, el cuarto ejemplo implica un buen equilibrio de cambios y rotondas, pero la recompensa por especificaciones de crecimiento múltiple es una estructura más clara (al menos en el nivel de sintaxis de entrada; el árbol real es un asunto diferente).

\begin{forest}
  for tree={anchor=center}, 
  forked edges,
  [0
    [1, subtree grow=west
      [1a][1b]
    ]
    [2, subtree grow=west
      [2a][2b]
    ]
    [3, subtree grow'=east
      [3a][3b]
    ]
    [4, subtree grow'=east
      [4a]
      [4b
        [x, subtree grow'=east[x1][x2]]
        [y, subtree grow=south[y1][y2]]
      ]
    ]
  ]
\end{forest}

Debajo del capó, ambos subtree growy subtree grow'llaman a un estilo llamado wild branching.

  subtree grow/.style={%
    wild branching={grow=#1},
  }, 
  subtree grow'/.style={%
    wild branching={grow'=#1},
  },

wild branchingno hace nada que no puedas hacer por ti mismo con el código de Sandy G y un par de ajustes. Utiliza una variedad de registros y opciones de bosque personalizados (para aquellos que no están familiarizados con esta terminología, una "opción" es una configuración para un nodo en un árbol, mientras que un "registro" se aplica a todo el árbol).

Opciones:

  declare boolean={wild children}{0},
  declare boolean={wild child}{0},
  declare keylist={tame ones}{},
  declare keylist={wild siblings}{},
  declare boolean={wild leader}{0},

El argumento final es el valor inicial de todos los nodos de todos los árboles.

Registros:

  declare boolean register={wild tree},
  wild tree=0,

También necesitamos algunos estilos simples:

  append me/.style={append={!id=#1},do dynamics},
  prepend me/.style={prepend={!id=#1},do dynamics},
  wild phantom/.style={%
    node options/.option=!u.node options,
    content/.process={Ow{!u.content}{\phantom{##1}}},
    child anchor/.option=!1.child anchor,
    anchor/.option=!1.anchor,
    parent anchor/.option=!1.parent anchor,
    opacity=0,
    no edge,
  },

y utilicé un paso personalizado

  define long step={wild children by growth}{}{%
    sort by={>O{grow}},sort'={filter={children}{>O{wild child}}}
  },

Dividí el estilo en partes porque se estaba volviendo un poco largo. wild branchingllamadas do tamenessy do wildnesssegún corresponda.

do tamenessinserta un nodo adicional para los subárboles que crecen en la dirección predeterminada, cuando uno de sus hermanos usa subtree growo subtree grow'.

  do tameness/.style={%
    where wild children={%
      tempboola=0,
      for children={%
        if wild child={}{%
          if tempboola={%
            !u.tame ones+/.option=id,
          }{%
            tempboola,
            replace by={%
              [,
                append,
                delay={%
                  if={>O_={!u.tame ones}{}}{}{%
                    split option={!u.tame ones}{,}{append me},
                  },
                  wild phantom,
                },
              ]%                  
            },
          },
        },
      },            
    }{},  
  },

do wildnessaverigua cuándo crear un nuevo nodo adicional para una nueva dirección de crecimiento y cuándo se debe agregar el subárbol a una adición existente. Aquí es donde se utiliza el paso personalizado definido anteriormente: garantiza que visitemos a los hermanos en orden según su dirección de crecimiento, lo que facilita la compilación de listas de cuáles pertenecen juntos.

  do wildness/.style={%
    where wild children={%
      tempcounta'=9999,
      for wild children by growth={%
        if={>OR= {grow}{tempcounta} }
        {%
          tempkeylista'=,
          for children={%
            tempkeylista+/.option=id,
          },
          for nodewalk={%
            until={>O{wild leader}}{next},
            if wild siblings={}{%
              wild siblings/.register=tempkeylista
            }{%
              wild siblings+/.register=tempkeylista
            }%
          }{%
          },
          before packing={remove},
        }{%
          wild leader,
          tempcounta/.option=grow,
          before packing={%
            if wild siblings={}{}{%
              split option={wild siblings}{,}{prepend me},
            },
          },
        },
      },
    }{},  
  },

Este método crea más nodos que el de Sandy G, pero los extras se eliminan antes de que se empaquete el árbol. No obstante, la estructura del árbol final difiere porque wild branchingse modifica ly santes de que se empaquete el nodo principal. En teoría, esto debería dar lugar a menos situaciones que requieran intervención manual. Pero la teoría no es, como todos sabemos, práctica.

  wild branching/.style={% 
    if id=1{for tree={#1}}{%
      !u.wild children,
      delay={%
        replace by={%
          [,
            wild child,
            append,
            delay={%
              wild phantom,
              for tree={#1},          
            },
          ]%
        },
      },
      if wild tree={}{%
        wild tree,
        !root.before typesetting nodes={%
          do tameness,
          do wildness,
        },
        !root.before packing={%
          delay={
            where wild children={%
              after packing node={%
                for children={l'=0pt,s'=0pt},
              },
            }{},
          },
        },
      },
    },
  },
  wild branching/.default={},

Tenga en cuenta que subtree grow/ subtree grow'no está diseñado para configurarse para el nodo raíz. Si lo son, wild branchingsimplemente se aplica growo grow'al árbol, sin invocar nada especial.

wild branchingProbablemente no debería tener una .defaultconfiguración, pero por alguna razón que ahora no recuerdo, he definido una.

Código:

\documentclass[a4paper,landscape]{article}
\usepackage[scale=.8]{geometry}
% ateb: https://tex.stackexchange.com/a/705635/ addaswyd o ateb Sandy G: https://tex.stackexchange.com/a/643061/
\usepackage{forest}
\useforestlibrary{edges}

\forestset{% https://tex.stackexchange.com/a/705635/
  declare boolean={wild children}{0},
  declare boolean={wild child}{0},
  declare keylist={tame ones}{},
  declare keylist={wild siblings}{},
  declare boolean={wild leader}{0},
  declare boolean register={wild tree},
  wild tree=0,
  append me/.style={append={!id=#1},do dynamics},
  prepend me/.style={prepend={!id=#1},do dynamics},
  wild phantom/.style={%
    node options/.option=!u.node options,
    content/.process={Ow{!u.content}{\phantom{##1}}},
    child anchor/.option=!1.child anchor,
    anchor/.option=!1.anchor,
    parent anchor/.option=!1.parent anchor,
    opacity=0,
    no edge,
  },
  define long step={wild children by growth}{}{%
    sort by={>O{grow}},sort'={filter={children}{>O{wild child}}}
  },
  do tameness/.style={%
    where wild children={%
      tempboola=0,
      for children={%
        if wild child={}{%
          if tempboola={%
            !u.tame ones+/.option=id,
          }{%
            tempboola,
            replace by={%
              [,
                append,
                delay={%
                  if={>O_={!u.tame ones}{}}{}{%
                    split option={!u.tame ones}{,}{append me},
                  },
                  wild phantom,
                },
              ]%                  
            },
          },
        },
      },            
    }{},  
  },
  do wildness/.style={%
    where wild children={%
      tempcounta'=9999,
      for wild children by growth={%
        if={>OR= {grow}{tempcounta} }
        {%
          tempkeylista'=,
          for children={%
            tempkeylista+/.option=id,
          },
          for nodewalk={%
            until={>O{wild leader}}{next},
            if wild siblings={}{%
              wild siblings/.register=tempkeylista
            }{%
              wild siblings+/.register=tempkeylista
            }%
          }{%
          },
          before packing={remove},
        }{%
          wild leader,
          tempcounta/.option=grow,
          before packing={%
            if wild siblings={}{}{%
              split option={wild siblings}{,}{prepend me},
            },
          },
        },
      },
    }{},  
  },
  wild branching/.style={% 
    if id=1{for tree={#1}}{%
      !u.wild children,
      delay={%
        replace by={%
          [,
            wild child,
            append,
            delay={%
              wild phantom,
              for tree={#1},          
            },
          ]%
        },
      },
      if wild tree={}{%
        wild tree,
        !root.before typesetting nodes={%
          do tameness,
          do wildness,
        },
        !root.before packing={%
          delay={
            where wild children={%
              after packing node={%
                for children={l'=0pt,s'=0pt},
              },
            }{},
          },
        },
      },
    },
  },
  wild branching/.default={},
  subtree grow/.style={%
    wild branching={grow=#1},
  }, 
  subtree grow'/.style={%
    wild branching={grow'=#1},
  },
}
\pagestyle{empty}
\begin{document}
\centering
\begin{forest}
  [root
    [child 1 
      [a][b]
    ]
    [child 2, subtree grow=150
      [c][d][e]
    ]
    [child 3, subtree grow'=30
      [f][g]
    ]
  ]
\end{forest}
\begin{forest}
  for tree={minimum height=4ex, anchor=center},
  forked edges,
  [R 
    [1, subtree grow'=east 
      [a][b]
    ]
    [2, subtree grow'=east 
      [c][d]
    ]
    [3, subtree grow'=east 
      [e][f]
    ]
    [4, subtree grow=west 
      [g][h]
    ]
    [5, subtree grow=west 
      [i][j]
    ]
    [6, subtree grow=west 
      [k][l]
    ]
  ]
\end{forest}
\begin{forest}
  for tree={minimum width=2.5em, anchor=center, circle, draw},
  [c
    [a, subtree grow'=north
      [a1][a2]
    ]
    [b, subtree grow'=north
      [b1][b2]
    ]
    [d
      [d1][d2]
    ]
    [e
      [e1][e2]
    ]
  ]
\end{forest}
\begin{forest}
  for tree={anchor=center}, 
  forked edges,
  [0
    [1, subtree grow=west
      [1a][1b]
    ]
    [2, subtree grow=west
      [2a][2b]
    ]
    [3, subtree grow'=east
      [3a][3b]
    ]
    [4, subtree grow'=east
      [4a]
      [4b
        [x, subtree grow'=east[x1][x2]]
        [y, subtree grow=south[y1][y2]]
      ]
    ]
  ]
\end{forest}

\end{document}

información relacionada