1
2## ----------------------------------------------------------------
3##
4##   IGraph R package
5##   Copyright (C) 2003-2014  Gabor Csardi <csardi.gabor@gmail.com>
6##   334 Harvard street, Cambridge, MA 02139 USA
7##
8##   This program is free software; you can redistribute it and/or modify
9##   it under the terms of the GNU General Public License as published by
10##   the Free Software Foundation; either version 2 of the License, or
11##   (at your option) any later version.
12##
13##   This program is distributed in the hope that it will be useful,
14##   but WITHOUT ANY WARRANTY; without even the implied warranty of
15##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16##   GNU General Public License for more details.
17##
18##   You should have received a copy of the GNU General Public License
19##   along with this program; if not, write to the Free Software
20##   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
21##   02110-1301 USA
22##
23## ----------------------------------------------------------------
24
25
26## ----------------------------------------------------------------
27## This is the new layout API
28## ----------------------------------------------------------------
29
30
31#' Graph layouts
32#'
33#' This is a generic function to apply a layout function to
34#' a graph.
35#'
36#' There are two ways to calculate graph layouts in igraph.
37#' The first way is to call a layout function (they all have
38#' prefix \code{layout_} on a graph, to get the vertex coordinates.
39#'
40#' The second way (new in igraph 0.8.0), has two steps, and it
41#' is more flexible. First you call a layout specification
42#' function (the one without the \code{layout_} prefix, and
43#' then \code{layout_} (or \code{\link{add_layout_}}) to
44#' perform the layouting.
45#'
46#' The second way is preferred, as it is more flexible. It allows
47#' operations before and after the layouting. E.g. using the
48#' \code{component_wise} argument, the layout can be calculated
49#' separately for each component, and then merged to get the
50#' final results.
51#'
52#' @aliases layout
53#' @section Modifiers:
54#' Modifiers modify how a layout calculation is performed.
55#' Currently implemented modifiers: \itemize{
56#'   \item \code{component_wise} calculates the layout separately
57#'     for each component of the graph, and then merges
58#'     them.
59#'   \item \code{normalize} scales the layout to a square.
60#' }
61#'
62#' @param graph The input graph.
63#' @param layout The layout specification. It must be a call
64#'   to a layout specification function.
65#' @param ... Further modifiers, see a complete list below.
66#'   For the \code{print} methods, it is ignored.
67#' @return The return value of the layout function, usually a
68#'   two column matrix. For 3D layouts a three column matrix.
69#'
70#' @seealso \code{\link{add_layout_}} to add the layout to the
71#'   graph as an attribute.
72#' @export
73#' @family graph layouts
74#' @examples
75#' g <- make_ring(10) + make_full_graph(5)
76#' coords <- layout_(g, as_star())
77#' plot(g, layout = coords)
78
79layout_ <- function(graph, layout, ...) {
80
81  modifiers <- list(...)
82  stopifnot(all(sapply(modifiers, inherits,
83                       what = "igraph_layout_modifier")))
84
85  ids <- sapply(modifiers, "[[", "id")
86  stopifnot(all(ids %in% c("component_wise", "normalize")))
87  if (anyDuplicated(ids)) stop("Duplicate modifiers")
88  names(modifiers) <- ids
89
90  ## TODO: better, generic mechanism for modifiers
91  if ("component_wise" %in% ids) {
92    graph$id <- seq(vcount(graph))
93    comps <- decompose(graph)
94    coords <- lapply(comps, function(comp) {
95      do_call(layout$fun, list(graph = comp), layout$args)
96    })
97    all_coords <- merge_coords(
98      comps,
99      coords,
100      method = modifiers[["component_wise"]]$args$merge_method
101    )
102    all_coords[ unlist(sapply(comps, vertex_attr, "id")), ] <- all_coords[]
103    result <- all_coords
104
105  } else {
106    result <- do_call(layout$fun, list(graph = graph), layout$args)
107  }
108
109  if ("normalize" %in% ids) {
110    result <- do_call(norm_coords, list(result),
111                      modifiers[["normalize"]]$args)
112  }
113
114  result
115}
116
117
118#' Add layout to graph
119#'
120#' @param graph The input graph.
121#' @param ... Additional arguments are passed to \code{\link{layout_}}.
122#' @param overwrite Whether to overwrite the layout of the graph,
123#'    if it already has one.
124#' @return The input graph, with the layout added.
125#'
126#' @seealso \code{\link{layout_}} for a description of the layout API.
127#' @export
128#' @family graph layouts
129#' @examples
130#' (make_star(11) + make_star(11)) %>%
131#'   add_layout_(as_star(), component_wise()) %>%
132#'   plot()
133
134add_layout_ <- function(graph, ..., overwrite = TRUE) {
135  if (overwrite && 'layout' %in% graph_attr_names(graph)) {
136    graph <- delete_graph_attr(graph, 'layout')
137  }
138  graph$layout <- layout_(graph, ...)
139  graph
140}
141
142
143layout_spec <- function(fun, ...) {
144  my_call <- match.call(sys.function(1), sys.call(1))
145  my_call[[1]] <- substitute(fun)
146  structure(
147    list(
148      fun = fun,
149      call_str = sub("(", "(<graph>, ", deparse(my_call), fixed = TRUE),
150      args = list(...)
151    ),
152    class = "igraph_layout_spec"
153  )
154}
155
156
157#' @rdname layout_
158#' @param x The layout specification
159#' @method print igraph_layout_spec
160#' @export
161
162print.igraph_layout_spec <- function(x, ...) {
163  cat(paste(
164    sep = "",
165    "igraph layout specification, see ?layout_:\n",
166    x$call_str, "\n"
167  ))
168}
169
170
171layout_modifier <- function(...) {
172  structure(
173    list(...),
174    class = "igraph_layout_modifier"
175  )
176}
177
178
179#' @rdname layout_
180#' @method print igraph_layout_modifier
181#' @export
182
183print.igraph_layout_modifier <- function(x, ...) {
184  cat(sep = "", "igraph layout modifier: ", x$id, ".\n")
185}
186
187#' Component-wise layout
188#'
189#' This is a layout modifier function, and it can be used
190#' to calculate the layout separately for each component
191#' of the graph.
192#'
193#' @param merge_method Merging algorithm, the \code{method}
194#'   argument of \code{\link{merge_coords}}.
195#'
196#' @family layout modifiers
197#' @family graph layouts
198#' @seealso \code{\link{merge_coords}}, \code{\link{layout_}}.
199#' @export
200#' @examples
201#' g <- make_ring(10) + make_ring(10)
202#' g %>%
203#'   add_layout_(in_circle(), component_wise()) %>%
204#'   plot()
205
206component_wise <- function(merge_method = "dla") {
207
208  args <- grab_args()
209
210  layout_modifier(
211    id = "component_wise",
212    args = args
213  )
214}
215
216#' Normalize layout
217#'
218#' Scale coordinates of a layout.
219#'
220#' @param xmin,xmax Minimum and maximum for x coordinates.
221#' @param ymin,ymax Minimum and maximum for y coordinates.
222#' @param zmin,zmax Minimum and maximum for z coordinates.
223#'
224#' @family layout modifiers
225#' @family graph layouts
226#' @seealso \code{\link{merge_coords}}, \code{\link{layout_}}.
227#' @export
228#' @examples
229#' layout_(make_ring(10), with_fr(), normalize())
230
231normalize <- function(xmin = -1, xmax = 1, ymin = xmin, ymax = xmax,
232                      zmin = xmin, zmax = xmax) {
233
234  args <- grab_args()
235
236  layout_modifier(
237    id = "normalize",
238    args = args
239  )
240}
241
242## ----------------------------------------------------------------
243## Layout definitions for the new API
244## ----------------------------------------------------------------
245
246
247#' Simple two-row layout for bipartite graphs
248#'
249#' Minimize edge-crossings in a simple two-row (or column) layout for bipartite
250#' graphs.
251#'
252#' The layout is created by first placing the vertices in two rows, according
253#' to their types. Then the positions within the rows are optimized to minimize
254#' edge crossings, using the Sugiyama algorithm (see
255#' \code{\link{layout_with_sugiyama}}).
256#'
257#' @aliases layout_as_bipartite layout.bipartite
258#' @param graph The bipartite input graph. It should have a logical
259#' \sQuote{\code{type}} vertex attribute, or the \code{types} argument must be
260#' given.
261#' @param types A logical vector, the vertex types. If this argument is
262#' \code{NULL} (the default), then the \sQuote{\code{type}} vertex attribute is
263#' used.
264#' @param hgap Real scalar, the minimum horizontal gap between vertices in the
265#' same layer.
266#' @param vgap Real scalar, the distance between the two layers.
267#' @param maxiter Integer scalar, the maximum number of iterations in the
268#' crossing minimization stage. 100 is a reasonable default; if you feel that
269#' you have too many edge crossings, increase this.
270#' @return A matrix with two columns and as many rows as the number of vertices
271#' in the input graph.
272#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
273#' @seealso \code{\link{layout_with_sugiyama}}
274#' @keywords graphs
275#' @export
276#' @family graph layouts
277#' @examples
278#' # Random bipartite graph
279#' inc <- matrix(sample(0:1, 50, replace = TRUE, prob=c(2,1)), 10, 5)
280#' g <- graph_from_incidence_matrix(inc)
281#' plot(g, layout = layout_as_bipartite,
282#'      vertex.color=c("green","cyan")[V(g)$type+1])
283#'
284#' # Two columns
285#' g %>%
286#'   add_layout_(as_bipartite()) %>%
287#'   plot()
288
289layout_as_bipartite <- function(graph, types = NULL, hgap = 1, vgap = 1,
290                                maxiter = 100) {
291
292  ## Argument checks
293  if (!is_igraph(graph)) { stop("Not a graph object") }
294  types <- handle_vertex_type_arg(types, graph)
295  hgap <- as.numeric(hgap)
296  vgap <- as.numeric(vgap)
297  maxiter <- as.integer(maxiter)
298
299  on.exit(.Call(C_R_igraph_finalizer) )
300
301  ## Function call
302  res <- .Call(C_R_igraph_layout_bipartite, graph, types, hgap, vgap, maxiter)
303
304  res
305}
306
307
308#' @rdname layout_as_bipartite
309#' @param ... Arguments to pass to \code{layout_as_bipartite}.
310#' @export
311
312as_bipartite <- function(...) layout_spec(layout_as_bipartite, ...)
313
314
315## ----------------------------------------------------------------
316
317
318#' Generate coordinates to place the vertices of a graph in a star-shape
319#'
320#' A simple layout generator, that places one vertex in the center of a circle
321#' and the rest of the vertices equidistantly on the perimeter.
322#'
323#' It is possible to choose the vertex that will be in the center, and the
324#' order of the vertices can be also given.
325#'
326#' @aliases layout_as_star layout.star
327#' @param graph The graph to layout.
328#' @param center The id of the vertex to put in the center. By default it is
329#' the first vertex.
330#' @param order Numeric vector, the order of the vertices along the perimeter.
331#' The default ordering is given by the vertex ids.
332#' @return A matrix with two columns and as many rows as the number of vertices
333#' in the input graph.
334#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
335#' @seealso \code{\link{layout}} and \code{\link{layout.drl}} for other layout
336#' algorithms, \code{\link{plot.igraph}} and \code{\link{tkplot}} on how to
337#' plot graphs and \code{\link{star}} on how to create ring graphs.
338#' @keywords graphs
339#' @export
340#' @family graph layouts
341#' @examples
342#'
343#' g <- make_star(10)
344#' layout_as_star(g)
345#'
346#' ## Alternative form
347#' layout_(g, as_star())
348
349layout_as_star <- function(graph, center=V(graph)[1], order=NULL) {
350  # Argument checks
351  if (!is_igraph(graph)) { stop("Not a graph object") }
352  center <- as.igraph.vs(graph, center)
353  if (!is.null(order)) order <- as.numeric(order)-1
354
355  on.exit(.Call(C_R_igraph_finalizer) )
356  # Function call
357  res <- .Call(C_R_igraph_layout_star, graph, center-1, order)
358
359  res
360}
361
362
363#' @rdname layout_as_star
364#' @param ... Arguments to pass to \code{layout_as_star}.
365#' @export
366
367as_star <- function(...) layout_spec(layout_as_star, ...)
368
369
370## ----------------------------------------------------------------
371
372
373#' The Reingold-Tilford graph layout algorithm
374#'
375#' A tree-like layout, it is perfect for trees, acceptable for graphs with not
376#' too many cycles.
377#'
378#' Arranges the nodes in a tree where the given node is used as the root.  The
379#' tree is directed downwards and the parents are centered above its children.
380#' For the exact algorithm, the reference below.
381#'
382#' If the given graph is not a tree, a breadth-first search is executed first
383#' to obtain a possible spanning tree.
384#'
385#' @param graph The input graph.
386#' @param root The index of the root vertex or root vertices.  If this is a
387#' non-empty vector then the supplied vertex ids are used as the roots of the
388#' trees (or a single tree if the graph is connected).  If it is an empty
389#' vector, then the root vertices are automatically calculated based on
390#' topological sorting, performed with the opposite mode than the \code{mode}
391#' argument. After the vertices have been sorted, one is selected from each
392#' component.
393#' @param circular Logical scalar, whether to plot the tree in a circular
394#' fashion. Defaults to \code{FALSE}, so the tree branches are going bottom-up
395#' (or top-down, see the \code{flip.y} argument.
396#' @param rootlevel This argument can be useful when drawing forests which are
397#' not trees (i.e. they are unconnected and have tree components). It specifies
398#' the level of the root vertices for every tree in the forest. It is only
399#' considered if the \code{roots} argument is not an empty vector.
400#' @param mode Specifies which edges to consider when building the tree.  If it
401#' is \sQuote{out}, then only the outgoing, if it is \sQuote{in}, then only the
402#' incoming edges of a parent are considered. If it is \sQuote{all} then all
403#' edges are used (this was the behavior in igraph 0.5 and before). This
404#' parameter also influences how the root vertices are calculated, if they are
405#' not given. See the \code{roots} parameter.
406#' @param flip.y Logical scalar, whether to flip the \sQuote{y} coordinates.
407#' The default is flipping because that puts the root vertex on the top.
408#' @return A numeric matrix with two columns, and one row for each vertex.
409#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
410#' \email{csardi.gabor@@gmail.com}
411#' @references Reingold, E and Tilford, J (1981). Tidier drawing of trees.
412#' \emph{IEEE Trans. on Softw. Eng.}, SE-7(2):223--228.
413#' @keywords graphs
414#' @export
415#' @family graph layouts
416#' @examples
417#'
418#' tree <- make_tree(20, 3)
419#' plot(tree, layout=layout_as_tree)
420#' plot(tree, layout=layout_as_tree(tree, flip.y=FALSE))
421#' plot(tree, layout=layout_as_tree(tree, circular=TRUE))
422#'
423#' tree2 <- make_tree(10, 3) + make_tree(10, 2)
424#' plot(tree2, layout=layout_as_tree)
425#' plot(tree2, layout=layout_as_tree(tree2, root=c(1,11),
426#'                                            rootlevel=c(2,1)))
427
428layout_as_tree <- function(graph, root=numeric(), circular=FALSE,
429                           rootlevel=numeric(), mode=c("out", "in", "all"),
430                           flip.y=TRUE) {
431
432  if (!is_igraph(graph)) {
433    stop("Not a graph object")
434  }
435  root <- as.igraph.vs(graph, root)-1
436  circular <- as.logical(circular)
437  rootlevel <- as.double(rootlevel)
438  mode <- switch(igraph.match.arg(mode), "out"=1, "in"=2, "all"=3,
439                 "total"=3)
440  flip.y <- as.logical(flip.y)
441
442  on.exit(.Call(C_R_igraph_finalizer) )
443  res <- .Call(C_R_igraph_layout_reingold_tilford, graph, root, mode,
444               rootlevel, circular)
445  if (flip.y) { res[,2] <- max(res[,2])-res[,2] }
446  res
447}
448
449
450#' @rdname layout_as_tree
451#' @param ... Passed to \code{layout_as_tree}.
452#' @export
453
454as_tree <- function(...) layout_spec(layout_as_tree, ...)
455
456#' @export
457#' @rdname layout.deprecated
458
459layout.reingold.tilford <- function(..., params = list()) {
460  do_call(layout_as_tree, .args = c(list(...), params))
461}
462
463## ----------------------------------------------------------------
464
465
466#' Graph layout with vertices on a circle.
467#'
468#' Place vertices on a circle, in the order of their vertex ids.
469#'
470#' If you want to order the vertices differently, then permute them using the
471#' \code{\link{permute}} function.
472#'
473#' @param graph The input graph.
474#' @param order The vertices to place on the circle, in the order of their
475#' desired placement. Vertices that are not included here will be placed at
476#' (0,0).
477#' @return A numeric matrix with two columns, and one row for each vertex.
478#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
479#' @keywords graphs
480#' @export
481#' @family graph layouts
482#' @examples
483#'
484#' ## Place vertices on a circle, order them according to their
485#' ## community
486#' \dontrun{
487#' library(igraphdata)
488#' data(karate)
489#' karate_groups <- cluster_optimal(karate)
490#' coords <- layout_in_circle(karate, order =
491#'           order(membership(karate_groups)))
492#' V(karate)$label <- sub("Actor ", "", V(karate)$name)
493#' V(karate)$label.color <- membership(karate_groups)
494#' V(karate)$shape <- "none"
495#' plot(karate, layout = coords)
496#' }
497
498layout_in_circle <- function(graph, order=V(graph)) {
499  if (!is_igraph(graph)) {
500    stop("Not a graph object")
501  }
502  order <- as.igraph.vs(graph, order) - 1L
503  on.exit(.Call(C_R_igraph_finalizer) )
504  .Call(C_R_igraph_layout_circle, graph, order)
505}
506
507#' @rdname layout_in_circle
508#' @param ... Passed to \code{layout_in_circle}.
509#' @export
510
511in_circle <- function(...) layout_spec(layout_in_circle, ...)
512
513#' @export
514#' @rdname layout.deprecated
515
516layout.circle <- function(..., params = list()) {
517  do_call(layout_in_circle, .args = c(list(...), params))
518}
519
520## ----------------------------------------------------------------
521
522
523#' Choose an appropriate graph layout algorithm automatically
524#'
525#' This function tries to choose an appropriate graph layout algorithm for the
526#' graph, automatically, based on a simple algorithm. See details below.
527#'
528#' \code{layout_nicely} tries to choose an appropriate layout function for the
529#' supplied graph, and uses that to generate the layout. The current
530#' implementation works like this: \enumerate{ \item If the graph has a graph
531#' attribute called \sQuote{layout}, then this is used. If this attribute is an
532#' R function, then it is called, with the graph and any other extra arguments.
533#' \item Otherwise, if the graph has vertex attributes called \sQuote{x} and
534#' \sQuote{y}, then these are used as coordinates. If the graph has an
535#' additional \sQuote{z} vertex attribute, that is also used.  \item Otherwise,
536#' if the graph is connected and has less than 1000 vertices, the
537#' Fruchterman-Reingold layout is used, by calling \code{layout_with_fr}.
538#' \item Otherwise the DrL layout is used, \code{layout_with_drl} is called.  }
539#'
540#' @aliases layout.auto
541#' @param graph The input graph
542#' @param dim Dimensions, should be 2 or 3.
543#' @param \dots For \code{layout_nicely} the extra arguments are passed to
544#'   the real layout function. For \code{nicely} all argument are passed to
545#'   \code{layout_nicely}.
546#' @return A numeric matrix with two or three columns.
547#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
548#' @seealso \code{\link{plot.igraph}}
549#' @keywords graphs
550#' @export
551#' @family graph layouts
552
553layout_nicely <- function(graph, dim=2, ...) {
554
555  ## 1. If there is a 'layout' graph attribute, we just use that.
556  ## 2. Otherwise, if there are vertex attributes called 'x' and 'y',
557  ##    we use those (and the 'z' vertex attribute as well, if present).
558  ## 3. Otherwise, if the graph is small (<1000) we use
559  ##    the Fruchterman-Reingold layout.
560  ## 5. Otherwise we use the DrL layout generator.
561
562  if ("layout" %in% graph_attr_names(graph)) {
563    lay <- graph_attr(graph, "layout")
564    if (is.function(lay)) {
565      lay(graph, ...)
566    } else {
567      lay
568    }
569
570  } else if ( all(c("x", "y") %in% vertex_attr_names(graph)) ) {
571    if ("z" %in% vertex_attr_names(graph)) {
572      cbind(V(graph)$x, V(graph)$y, V(graph)$z)
573    } else {
574      cbind(V(graph)$x, V(graph)$y)
575    }
576
577  } else if (vcount(graph) < 1000) {
578    layout_with_fr(graph, dim=dim, ...)
579
580  } else {
581    layout_with_drl(graph, dim=dim, ...)
582  }
583
584}
585
586
587#' @rdname layout_nicely
588#' @export
589
590nicely <- function(...) layout_spec(layout_nicely, ...)
591
592
593## ----------------------------------------------------------------
594
595
596#' Simple grid layout
597#'
598#' This layout places vertices on a rectangular grid, in two or three
599#' dimensions.
600#'
601#' The function places the vertices on a simple rectangular grid, one after the
602#' other. If you want to change the order of the vertices, then see the
603#' \code{\link{permute}} function.
604#'
605#' @aliases layout_on_grid layout.grid layout.grid.3d
606#' @param graph The input graph.
607#' @param width The number of vertices in a single row of the grid. If this is
608#' zero or negative, then for 2d layouts the width of the grid will be the
609#' square root of the number of vertices in the graph, rounded up to the next
610#' integer. Similarly, it will be the cube root for 3d layouts.
611#' @param height The number of vertices in a single column of the grid, for
612#' three dimensional layouts. If this is zero or negative, then it is
613#' determinted automatically.
614#' @param dim Two or three. Whether to make 2d or a 3d layout.
615#' @return A two-column or three-column matrix.
616#' @author Tamas Nepusz \email{ntamas@@gmail.com}
617#' @seealso \code{\link{layout}} for other layout generators
618#' @keywords graphs
619#' @export
620#' @family graph layouts
621#' @examples
622#'
623#' g <- make_lattice( c(3,3) )
624#' layout_on_grid(g)
625#'
626#' g2 <- make_lattice( c(3,3,3) )
627#' layout_on_grid(g2, dim = 3)
628#'
629#' \dontrun{
630#' plot(g, layout=layout_on_grid)
631#' rglplot(g, layout=layout_on_grid(g, dim = 3))
632#' }
633
634layout_on_grid <- function(graph, width = 0, height = 0, dim = 2) {
635  # Argument checks
636  if (!is_igraph(graph)) { stop("Not a graph object") }
637  width <- as.integer(width)
638  dim <- as.integer(dim)
639  stopifnot(dim == 2 || dim == 3)
640  if (dim == 3) { height <- as.integer(height) }
641
642  on.exit(.Call(C_R_igraph_finalizer) )
643  # Function call
644  if (dim == 2) {
645    res <- .Call(C_R_igraph_layout_grid, graph, width)
646  } else {
647    res <- .Call(C_R_igraph_layout_grid_3d, graph, width, height)
648  }
649
650  res
651}
652
653
654#' @rdname layout_on_grid
655#' @param ... Passed to \code{layout_on_grid}.
656#' @export
657
658on_grid <- function(...) layout_spec(layout_on_grid, ...)
659
660
661#' @rdname layout_on_grid
662#' @export
663
664layout.grid.3d <- function(graph, width=0, height=0) {
665  .Deprecated("layout_on_grid", msg = paste0("layout.grid.3d is deprecated from\n",
666      "igraph 0.8.0, please use layout_on_grid instead"))
667  # Argument checks
668  if (!is_igraph(graph)) { stop("Not a graph object") }
669  width <- as.integer(width)
670  height <- as.integer(height)
671
672  on.exit(.Call(C_R_igraph_finalizer) )
673  # Function call
674  res <- .Call(C_R_igraph_layout_grid_3d, graph, width, height)
675
676  res
677}
678
679## ----------------------------------------------------------------
680
681
682#' Graph layout with vertices on the surface of a sphere
683#'
684#' Place vertices on a sphere, approximately uniformly, in the order of their
685#' vertex ids.
686#'
687#' \code{layout_on_sphere} places the vertices (approximately) uniformly on the
688#' surface of a sphere, this is thus a 3d layout. It is not clear however what
689#' \dQuote{uniformly on a sphere} means.
690#'
691#' If you want to order the vertices differently, then permute them using the
692#' \code{\link{permute}} function.
693#'
694#' @param graph The input graph.
695#' @return A numeric matrix with three columns, and one row for each vertex.
696#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
697#' @keywords graphs
698#' @export
699#' @family graph layouts
700
701layout_on_sphere <- function(graph) {
702  if (!is_igraph(graph)) {
703    stop("Not a graph object")
704  }
705  on.exit(.Call(C_R_igraph_finalizer) )
706  .Call(C_R_igraph_layout_sphere, graph)
707}
708
709
710#' @rdname layout_on_sphere
711#' @param ... Passed to \code{layout_on_sphere}.
712#' @export
713
714on_sphere <- function(...) layout_spec(layout_on_sphere, ...)
715
716#' @export
717#' @rdname layout.deprecated
718
719layout.sphere <- function(..., params = list()) {
720  do_call(layout_on_sphere, .args = c(list(...), params))
721}
722
723## ----------------------------------------------------------------
724
725
726#' Randomly place vertices on a plane or in 3d space
727#'
728#' This function uniformly randomly places the vertices of the graph in two or
729#' three dimensions.
730#'
731#' Randomly places vertices on a [-1,1] square (in 2d) or in a cube (in 3d). It
732#' is probably a useless layout, but it can use as a starting point for other
733#' layout generators.
734#'
735#' @param graph The input graph.
736#' @param dim Integer scalar, the dimension of the space to use. It must be 2
737#' or 3.
738#' @return A numeric matrix with two or three columns.
739#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
740#' @keywords graphs
741#' @export
742#' @family graph layouts
743
744layout_randomly <- function(graph, dim=2) {
745  if (!is_igraph(graph)) {
746    stop("Not a graph object")
747  }
748  if (dim==2) {
749    on.exit(.Call(C_R_igraph_finalizer) )
750    .Call(C_R_igraph_layout_random, graph)
751  } else if (dim==3) {
752    on.exit(.Call(C_R_igraph_finalizer) )
753    .Call(C_R_igraph_layout_random_3d, graph)
754  } else {
755    stop("Invalid `dim' value");
756  }
757}
758
759#' @rdname layout_randomly
760#' @param ... Parameters to pass to \code{layout_randomly}.
761#' @export
762
763randomly <- function(...) layout_spec(layout_randomly, ...)
764
765#' Deprecated layout functions
766#'
767#' Please use the new names, see \code{\link{layout_}}.
768#'
769#' @param ... Passed to the new layout functions.
770#' @param params Passed to the new layout functions as arguments.
771#' @export
772#' @rdname layout.deprecated
773
774layout.random <- function(..., params = list()) {
775  do_call(layout_randomly, .args = c(list(...), params))
776}
777
778
779## ----------------------------------------------------------------
780
781
782
783#' The Davidson-Harel layout algorithm
784#'
785#' Place vertices of a graph on the plane, according to the simulated annealing
786#' algorithm by Davidson and Harel.
787#'
788#' This function implements the algorithm by Davidson and Harel, see Ron
789#' Davidson, David Harel: Drawing Graphs Nicely Using Simulated Annealing. ACM
790#' Transactions on Graphics 15(4), pp. 301-331, 1996.
791#'
792#' The algorithm uses simulated annealing and a sophisticated energy function,
793#' which is unfortunately hard to parameterize for different graphs. The
794#' original publication did not disclose any parameter values, and the ones
795#' below were determined by experimentation.
796#'
797#' The algorithm consists of two phases, an annealing phase, and a fine-tuning
798#' phase. There is no simulated annealing in the second phase.
799#'
800#' Our implementation tries to follow the original publication, as much as
801#' possible. The only major difference is that coordinates are explicitly kept
802#' within the bounds of the rectangle of the layout.
803#'
804#' @aliases layout.davidson.harel
805#' @param graph The graph to lay out. Edge directions are ignored.
806#' @param coords Optional starting positions for the vertices. If this argument
807#' is not \code{NULL} then it should be an appropriate matrix of starting
808#' coordinates.
809#' @param maxiter Number of iterations to perform in the first phase.
810#' @param fineiter Number of iterations in the fine tuning phase.
811#' @param cool.fact Cooling factor.
812#' @param weight.node.dist Weight for the node-node distances component of the
813#' energy function.
814#' @param weight.border Weight for the distance from the border component of
815#' the energy function. It can be set to zero, if vertices are allowed to sit
816#' on the border.
817#' @param weight.edge.lengths Weight for the edge length component of the
818#' energy function.
819#' @param weight.edge.crossings Weight for the edge crossing component of the
820#' energy function.
821#' @param weight.node.edge.dist Weight for the node-edge distance component of
822#' the energy function.
823#' @return A two- or three-column matrix, each row giving the coordinates of a
824#' vertex, according to the ids of the vertex ids.
825#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
826#' @seealso \code{\link{layout_with_fr}},
827#' \code{\link{layout_with_kk}} for other layout algorithms.
828#' @references Ron Davidson, David Harel: Drawing Graphs Nicely Using Simulated
829#' Annealing. \emph{ACM Transactions on Graphics} 15(4), pp. 301-331, 1996.
830#' @export
831#' @family graph layouts
832#' @examples
833#'
834#' set.seed(42)
835#' ## Figures from the paper
836#' g_1b <- make_star(19, mode="undirected") + path(c(2:19, 2)) +
837#'   path(c(seq(2, 18, by=2), 2))
838#' plot(g_1b, layout=layout_with_dh)
839#'
840#' g_2 <- make_lattice(c(8, 3)) + edges(1,8, 9,16, 17,24)
841#' plot(g_2, layout=layout_with_dh)
842#'
843#' g_3 <- make_empty_graph(n=70)
844#' plot(g_3, layout=layout_with_dh)
845#'
846#' g_4 <- make_empty_graph(n=70, directed=FALSE) + edges(1:70)
847#' plot(g_4, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
848#'
849#' g_5a <- make_ring(24)
850#' plot(g_5a, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
851#'
852#' g_5b <- make_ring(40)
853#' plot(g_5b, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
854#'
855#' g_6 <- make_lattice(c(2,2,2))
856#' plot(g_6, layout=layout_with_dh)
857#'
858#' g_7 <- graph_from_literal(1:3:5 -- 2:4:6)
859#' plot(g_7, layout=layout_with_dh, vertex.label=V(g_7)$name)
860#'
861#' g_8 <- make_ring(5) + make_ring(10) + make_ring(5) +
862#'   edges(1,6, 2,8, 3, 10, 4,12, 5,14,
863#'         7,16, 9,17, 11,18, 13,19, 15,20)
864#' plot(g_8, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
865#'
866#' g_9 <- make_lattice(c(3,2,2))
867#' plot(g_9, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
868#'
869#' g_10 <- make_lattice(c(6,6))
870#' plot(g_10, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
871#'
872#' g_11a <- make_tree(31, 2, mode="undirected")
873#' plot(g_11a, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
874#'
875#' g_11b <- make_tree(21, 4, mode="undirected")
876#' plot(g_11b, layout=layout_with_dh, vertex.size=5, vertex.label=NA)
877#'
878#' g_12 <- make_empty_graph(n=37, directed=FALSE) +
879#'   path(1:5,10,22,31,37:33,27,16,6,1) + path(6,7,11,9,10) + path(16:22) +
880#'   path(27:31) + path(2,7,18,28,34) + path(3,8,11,19,29,32,35) +
881#'   path(4,9,20,30,36) + path(1,7,12,14,19,24,26,30,37) +
882#'   path(5,9,13,15,19,23,25,28,33) + path(3,12,16,25,35,26,22,13,3)
883#' plot(g_12,  layout=layout_with_dh, vertex.size=5, vertex.label=NA)
884
885layout_with_dh <- function(graph, coords=NULL, maxiter=10,
886           fineiter=max(10, log2(vcount(graph))), cool.fact=0.75,
887           weight.node.dist=1.0, weight.border=0.0,
888           weight.edge.lengths=edge_density(graph) / 10,
889           weight.edge.crossings=1.0 - sqrt(edge_density(graph)),
890           weight.node.edge.dist=0.2 * (1-edge_density(graph))) {
891
892  # Argument checks
893  if (!is_igraph(graph)) { stop("Not a graph object") }
894  if (!is.null(coords)) {
895    coords <- as.matrix(structure(as.double(coords), dim=dim(coords)))
896    use.seed <- TRUE
897  } else {
898    coords <- matrix(NA_real_, ncol=2, nrow=0)
899    use.seed <- FALSE
900  }
901  maxiter <- as.integer(maxiter)
902  fineiter <- as.integer(fineiter)
903  cool.fact <- as.numeric(cool.fact)
904  weight.node.dist <- as.numeric(weight.node.dist)
905  weight.border <- as.numeric(weight.border)
906  weight.edge.lengths <- as.numeric(weight.edge.lengths)
907  weight.edge.crossings <- as.numeric(weight.edge.crossings)
908  weight.node.edge.dist <- as.numeric(weight.node.edge.dist)
909
910  on.exit(.Call(C_R_igraph_finalizer) )
911  # Function call
912  res <- .Call(C_R_igraph_layout_davidson_harel, graph, coords, use.seed,
913               maxiter, fineiter, cool.fact, weight.node.dist,
914               weight.border, weight.edge.lengths, weight.edge.crossings,
915               weight.node.edge.dist)
916
917  res
918}
919
920
921#' @rdname layout_with_dh
922#' @param ... Passed to \code{layout_with_dh}.
923#' @export
924
925with_dh <- function(...) layout_spec(layout_with_dh, ...)
926
927
928
929## ----------------------------------------------------------------
930
931
932#' The Fruchterman-Reingold layout algorithm
933#'
934#' Place vertices on the plane using the force-directed layout algorithm by
935#' Fruchterman and Reingold.
936#'
937#' See the referenced paper below for the details of the algorithm.
938#'
939#' This function was rewritten from scratch in igraph version 0.8.0.
940#'
941#' @param graph The graph to lay out. Edge directions are ignored.
942#' @param coords Optional starting positions for the vertices. If this argument
943#' is not \code{NULL} then it should be an appropriate matrix of starting
944#' coordinates.
945#' @param dim Integer scalar, 2 or 3, the dimension of the layout.  Two
946#' dimensional layouts are places on a plane, three dimensional ones in the 3d
947#' space.
948#' @param niter Integer scalar, the number of iterations to perform.
949#' @param start.temp Real scalar, the start temperature. This is the maximum
950#' amount of movement alloved along one axis, within one step, for a vertex.
951#' Currently it is decreased linearly to zero during the iteration.
952#' @param grid Character scalar, whether to use the faster, but less accurate
953#' grid based implementation of the algorithm. By default (\dQuote{auto}), the
954#' grid-based implementation is used if the graph has more than one thousand
955#' vertices.
956#' @param weights A vector giving edge weights. The \code{weight} edge
957#' attribute is used by default, if present. If weights are given, then the
958#' attraction along the edges will be multiplied by the given edge weights.
959#' This places vertices connected with a highly weighted edge closer to
960#' each other.
961#' @param minx If not \code{NULL}, then it must be a numeric vector that gives
962#' lower boundaries for the \sQuote{x} coordinates of the vertices. The length
963#' of the vector must match the number of vertices in the graph.
964#' @param maxx Similar to \code{minx}, but gives the upper boundaries.
965#' @param miny Similar to \code{minx}, but gives the lower boundaries of the
966#' \sQuote{y} coordinates.
967#' @param maxy Similar to \code{minx}, but gives the upper boundaries of the
968#' \sQuote{y} coordinates.
969#' @param minz Similar to \code{minx}, but gives the lower boundaries of the
970#' \sQuote{z} coordinates.
971#' @param maxz Similar to \code{minx}, but gives the upper boundaries of the
972#' \sQuote{z} coordinates.
973#' @param coolexp,maxdelta,area,repulserad These arguments are not supported
974#' from igraph version 0.8.0 and are ignored (with a warning).
975#' @param maxiter A deprecated synonym of \code{niter}, for compatibility.
976#' @return A two- or three-column matrix, each row giving the coordinates of a
977#' vertex, according to the ids of the vertex ids.
978#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
979#' @seealso \code{\link{layout_with_drl}}, \code{\link{layout_with_kk}} for
980#' other layout algorithms.
981#' @references Fruchterman, T.M.J. and Reingold, E.M. (1991). Graph Drawing by
982#' Force-directed Placement. \emph{Software - Practice and Experience},
983#' 21(11):1129-1164.
984#' @export
985#' @family graph layouts
986#' @keywords graphs
987#' @examples
988#'
989#' # Fixing ego
990#' g <- sample_pa(20, m=2)
991#' minC <- rep(-Inf, vcount(g))
992#' maxC <- rep(Inf, vcount(g))
993#' minC[1] <- maxC[1] <- 0
994#' co <- layout_with_fr(g, minx=minC, maxx=maxC,
995#'                                   miny=minC, maxy=maxC)
996#' co[1,]
997#' plot(g, layout=co, vertex.size=30, edge.arrow.size=0.2,
998#'      vertex.label=c("ego", rep("", vcount(g)-1)), rescale=FALSE,
999#'      xlim=range(co[,1]), ylim=range(co[,2]), vertex.label.dist=0,
1000#'      vertex.label.color="red")
1001#' axis(1)
1002#' axis(2)
1003#'
1004layout_with_fr <- function(graph, coords=NULL, dim=2,
1005                            niter=500, start.temp=sqrt(vcount(graph)),
1006                            grid=c("auto", "grid", "nogrid"), weights=NULL,
1007                            minx=NULL, maxx=NULL, miny=NULL, maxy=NULL,
1008                            minz=NULL, maxz=NULL,
1009                            coolexp, maxdelta, area, repulserad, maxiter) {
1010
1011                                        # Argument checks
1012  if (!is_igraph(graph)) { stop("Not a graph object") }
1013  if (!is.null(coords)) {
1014    coords <- as.matrix(structure(as.double(coords), dim=dim(coords)))
1015  }
1016  dim <- as.integer(dim)
1017  if (dim != 2L && dim != 3L) {
1018    stop("Dimension must be two or three")
1019  }
1020  if (!missing(niter) && !missing(maxiter)) {
1021    stop("Both `niter' and `maxiter' are given, give only one of them")
1022  }
1023  if (!missing(maxiter)) niter <- maxiter
1024  niter <- as.integer(niter)
1025  start.temp <- as.numeric(start.temp)
1026
1027  grid <- igraph.match.arg(grid)
1028  grid <- switch(grid, "grid"=0L, "nogrid"=1L, "auto"=2L)
1029
1030  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
1031    weights <- E(graph)$weight
1032  }
1033  if (!is.null(weights) && any(!is.na(weights))) {
1034    weights <- as.numeric(weights)
1035  } else {
1036    weights <- NULL
1037  }
1038  if (!is.null(minx)) minx <- as.numeric(minx)
1039  if (!is.null(maxx)) maxx <- as.numeric(maxx)
1040  if (!is.null(miny)) miny <- as.numeric(miny)
1041  if (!is.null(maxy)) maxy <- as.numeric(maxy)
1042  if (!is.null(minz)) minz <- as.numeric(minz)
1043  if (!is.null(maxz)) maxz <- as.numeric(maxz)
1044  if (!missing(coolexp)) {
1045    warning("Argument `coolexp' is deprecated and has no effect")
1046  }
1047  if (!missing(maxdelta)) {
1048    warning("Argument `maxdelta' is deprecated and has no effect")
1049  }
1050  if (!missing(area)) {
1051    warning("Argument `area' is deprecated and has no effect")
1052  }
1053  if (!missing(repulserad)) {
1054    warning("Argument `repulserad' is deprecated and has no effect")
1055  }
1056
1057  on.exit(.Call(C_R_igraph_finalizer) )
1058  if (dim==2) {
1059    res <- .Call(C_R_igraph_layout_fruchterman_reingold, graph, coords,
1060                 niter, start.temp, weights, minx, maxx, miny, maxy, grid)
1061  } else {
1062    res <- .Call(C_R_igraph_layout_fruchterman_reingold_3d, graph, coords,
1063                 niter, start.temp, weights, minx, maxx, miny, maxy,
1064                 minz, maxz)
1065  }
1066  res
1067}
1068
1069
1070#' @rdname layout_with_fr
1071#' @param ... Passed to \code{layout_with_fr}.
1072#' @export
1073
1074with_fr <- function(...) layout_spec(layout_with_fr, ...)
1075
1076#' @export
1077#' @rdname layout.deprecated
1078
1079layout.fruchterman.reingold <- function(..., params = list()) {
1080  do_call(layout_with_fr, .args = c(list(...), params))
1081}
1082
1083## ----------------------------------------------------------------
1084
1085
1086#' The GEM layout algorithm
1087#'
1088#' Place vertices on the plane using the GEM force-directed layout algorithm.
1089#'
1090#' See the referenced paper below for the details of the algorithm.
1091#'
1092#' @aliases layout.gem
1093#' @param graph The input graph. Edge directions are ignored.
1094#' @param coords If not \code{NULL}, then the starting coordinates should be
1095#' given here, in a two or three column matrix, depending on the \code{dim}
1096#' argument.
1097#' @param maxiter The maximum number of iterations to perform. Updating a
1098#' single vertex counts as an iteration.  A reasonable default is 40 * n * n,
1099#' where n is the number of vertices. The original paper suggests 4 * n * n,
1100#' but this usually only works if the other parameters are set up carefully.
1101#' @param temp.max The maximum allowed local temperature. A reasonable default
1102#' is the number of vertices.
1103#' @param temp.min The global temperature at which the algorithm terminates
1104#' (even before reaching \code{maxiter} iterations). A reasonable default is
1105#' 1/10.
1106#' @param temp.init Initial local temperature of all vertices. A reasonable
1107#' default is the square root of the number of vertices.
1108#' @return A numeric matrix with two columns, and as many rows as the number of
1109#' vertices.
1110#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
1111#' @seealso \code{\link{layout_with_fr}},
1112#' \code{\link{plot.igraph}}, \code{\link{tkplot}}
1113#' @references Arne Frick, Andreas Ludwig, Heiko Mehldau: A Fast Adaptive
1114#' Layout Algorithm for Undirected Graphs, \emph{Proc. Graph Drawing 1994},
1115#' LNCS 894, pp. 388-403, 1995.
1116#' @export
1117#' @family graph layouts
1118#' @keywords graphs
1119#' @examples
1120#'
1121#' set.seed(42)
1122#' g <- make_ring(10)
1123#' plot(g, layout=layout_with_gem)
1124#'
1125layout_with_gem <- function(graph, coords=NULL, maxiter=40*vcount(graph)^2,
1126                       temp.max=vcount(graph), temp.min=1/10,
1127                       temp.init=sqrt(vcount(graph))) {
1128
1129  # Argument checks
1130  if (!is_igraph(graph)) { stop("Not a graph object") }
1131  if (!is.null(coords)) {
1132    coords <- as.matrix(structure(as.double(coords), dim=dim(coords)))
1133    use.seed <- TRUE
1134  } else {
1135    coords <- matrix(NA_real_, ncol=2, nrow=0)
1136    use.seed <- FALSE
1137  }
1138
1139  maxiter <- as.integer(maxiter)
1140  temp.max <- as.numeric(temp.max)
1141  temp.min <- as.numeric(temp.min)
1142  temp.init <- as.numeric(temp.init)
1143
1144  on.exit(.Call(C_R_igraph_finalizer) )
1145  # Function call
1146  res <- .Call(C_R_igraph_layout_gem, graph, coords, use.seed, maxiter,
1147               temp.max, temp.min, temp.init)
1148
1149  res
1150}
1151
1152
1153#' @rdname layout_with_gem
1154#' @param ... Passed to \code{layout_with_gem}.
1155#' @export
1156
1157with_gem <- function(...) layout_spec(layout_with_gem, ...)
1158
1159
1160## ----------------------------------------------------------------
1161
1162
1163#' The graphopt layout algorithm
1164#'
1165#' A force-directed layout algorithm, that scales relatively well to large
1166#' graphs.
1167#'
1168#' \code{layout_with_graphopt} is a port of the graphopt layout algorithm by Michael
1169#' Schmuhl. graphopt version 0.4.1 was rewritten in C and the support for
1170#' layers was removed (might be added later) and a code was a bit reorganized
1171#' to avoid some unnecessary steps is the node charge (see below) is zero.
1172#'
1173#' graphopt uses physical analogies for defining attracting and repelling
1174#' forces among the vertices and then the physical system is simulated until it
1175#' reaches an equilibrium. (There is no simulated annealing or anything like
1176#' that, so a stable fixed point is not guaranteed.)
1177#'
1178#' See also \url{http://www.schmuhl.org/graphopt/} for the original graphopt.
1179#'
1180#' @aliases layout.graphopt
1181#' @param graph The input graph.
1182#' @param start If given, then it should be a matrix with two columns and one
1183#' line for each vertex. This matrix will be used as starting positions for the
1184#' algorithm. If not given, then a random starting matrix is used.
1185#' @param niter Integer scalar, the number of iterations to perform.  Should be
1186#' a couple of hundred in general. If you have a large graph then you might
1187#' want to only do a few iterations and then check the result. If it is not
1188#' good enough you can feed it in again in the \code{start} argument. The
1189#' default value is 500.
1190#' @param charge The charge of the vertices, used to calculate electric
1191#' repulsion. The default is 0.001.
1192#' @param mass The mass of the vertices, used for the spring forces. The
1193#' default is 30.
1194#' @param spring.length The length of the springs, an integer number. The
1195#' default value is zero.
1196#' @param spring.constant The spring constant, the default value is one.
1197#' @param max.sa.movement Real constant, it gives the maximum amount of
1198#' movement allowed in a single step along a single axis. The default value is
1199#' 5.
1200#' @return A numeric matrix with two columns, and a row for each vertex.
1201#' @author Michael Schmuhl for the original graphopt code, rewritten and
1202#' wrapped by Gabor Csardi \email{csardi.gabor@@gmail.com}.
1203#' @keywords graphs
1204#' @export
1205#' @family graph layouts
1206
1207layout_with_graphopt <- function(graph, start=NULL, niter=500, charge=0.001,
1208                            mass=30, spring.length=0, spring.constant=1,
1209                            max.sa.movement=5) {
1210
1211  if (!is_igraph(graph)) {
1212    stop("Not a graph object")
1213  }
1214  if (!is.null(start)) {
1215    start <- structure(as.numeric(start), dim=dim(start))
1216  }
1217  niter <- as.double(niter)
1218  charge <- as.double(charge)
1219  mass <- as.double(mass)
1220  spring.length <- as.double(spring.length)
1221  spring.constant <- as.double(spring.constant)
1222  max.sa.movement <- as.double(max.sa.movement)
1223
1224  on.exit(.Call(C_R_igraph_finalizer) )
1225  .Call(C_R_igraph_layout_graphopt, graph, niter, charge, mass,
1226        spring.length, spring.constant, max.sa.movement, start)
1227}
1228
1229
1230#' @rdname layout_with_graphopt
1231#' @param ... Passed to \code{layout_with_graphopt}.
1232#' @export
1233
1234with_graphopt <- function(...) layout_spec(layout_with_graphopt, ...)
1235
1236
1237## ----------------------------------------------------------------
1238
1239
1240#' The Kamada-Kawai layout algorithm
1241#'
1242#' Place the vertices on the plane, or in the 3d space, based on a physical
1243#' model of springs.
1244#'
1245#' See the referenced paper below for the details of the algorithm.
1246#'
1247#' This function was rewritten from scratch in igraph version 0.8.0 and it
1248#' follows truthfully the original publication by Kamada and Kawai now.
1249#'
1250#' @param graph The input graph. Edge directions are ignored.
1251#' @param coords If not \code{NULL}, then the starting coordinates should be
1252#' given here, in a two or three column matrix, depending on the \code{dim}
1253#' argument.
1254#' @param dim Integer scalar, 2 or 3, the dimension of the layout.  Two
1255#' dimensional layouts are places on a plane, three dimensional ones in the 3d
1256#' space.
1257#' @param maxiter The maximum number of iterations to perform. The algorithm
1258#' might terminate earlier, see the \code{epsilon} argument.
1259#' @param epsilon Numeric scalar, the algorithm terminates, if the maximal
1260#' delta is less than this. (See the reference below for what delta means.) If
1261#' you set this to zero, then the function always performs \code{maxiter}
1262#' iterations.
1263#' @param kkconst Numeric scalar, the Kamada-Kawai vertex attraction constant.
1264#' Typical (and default) value is the number of vertices.
1265#' @param weights Edge weights, larger values will result longer edges.
1266#' Note that this is opposite to \code{\link{layout_with_fr}}.
1267#' @param minx If not \code{NULL}, then it must be a numeric vector that gives
1268#' lower boundaries for the \sQuote{x} coordinates of the vertices. The length
1269#' of the vector must match the number of vertices in the graph.
1270#' @param maxx Similar to \code{minx}, but gives the upper boundaries.
1271#' @param miny Similar to \code{minx}, but gives the lower boundaries of the
1272#' \sQuote{y} coordinates.
1273#' @param maxy Similar to \code{minx}, but gives the upper boundaries of the
1274#' \sQuote{y} coordinates.
1275#' @param minz Similar to \code{minx}, but gives the lower boundaries of the
1276#' \sQuote{z} coordinates.
1277#' @param maxz Similar to \code{minx}, but gives the upper boundaries of the
1278#' \sQuote{z} coordinates.
1279#' @param niter,sigma,initemp,coolexp These arguments are not supported from
1280#' igraph version 0.8.0 and are ignored (with a warning).
1281#' @param start Deprecated synonym for \code{coords}, for compatibility.
1282#' @return A numeric matrix with two (dim=2) or three (dim=3) columns, and as
1283#' many rows as the number of vertices, the x, y and potentially z coordinates
1284#' of the vertices.
1285#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
1286#' @seealso \code{\link{layout_with_drl}}, \code{\link{plot.igraph}},
1287#' \code{\link{tkplot}}
1288#' @references Kamada, T. and Kawai, S.: An Algorithm for Drawing General
1289#' Undirected Graphs. \emph{Information Processing Letters}, 31/1, 7--15, 1989.
1290#' @export
1291#' @family graph layouts
1292#' @keywords graphs
1293#' @examples
1294#'
1295#' g <- make_ring(10)
1296#' E(g)$weight <- rep(1:2, length.out=ecount(g))
1297#' plot(g, layout=layout_with_kk, edge.label=E(g)$weight)
1298#'
1299layout_with_kk <- function(graph, coords=NULL, dim=2,
1300                                maxiter=50*vcount(graph),
1301                                epsilon=0.0, kkconst=vcount(graph),
1302                                weights=NULL, minx=NULL, maxx=NULL,
1303                                miny=NULL, maxy=NULL, minz=NULL, maxz=NULL,
1304                                niter, sigma, initemp, coolexp, start) {
1305  # Argument checks
1306  if (!missing(coords) && !missing(start)) {
1307    stop("Both `coords' and `start' are given, give only one of them.")
1308  }
1309  if (!missing(start)) coords <- start
1310
1311  if (!is_igraph(graph)) { stop("Not a graph object") }
1312  if (!is.null(coords)) {
1313    coords <- as.matrix(structure(as.double(coords), dim=dim(coords)))
1314  }
1315  dim <- as.integer(dim)
1316  if (dim != 2L && dim != 3L) {
1317    stop("Dimension must be two or three")
1318  }
1319
1320  maxiter <- as.integer(maxiter)
1321  epsilon <- as.numeric(epsilon)
1322  kkconst <- as.numeric(kkconst)
1323  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
1324    weights <- E(graph)$weight
1325  }
1326  if (!is.null(weights) && any(!is.na(weights))) {
1327    weights <- as.numeric(weights)
1328  } else {
1329    weights <- NULL
1330  }
1331  if (!is.null(minx)) minx <- as.numeric(minx)
1332  if (!is.null(maxx)) maxx <- as.numeric(maxx)
1333  if (!is.null(miny)) miny <- as.numeric(miny)
1334  if (!is.null(maxy)) maxy <- as.numeric(maxy)
1335  if (!is.null(minz)) minz <- as.numeric(minz)
1336  if (!is.null(maxz)) maxz <- as.numeric(maxz)
1337
1338  if (!missing(niter)) {
1339    warning("Argument `niter' is deprecated and has no effect")
1340  }
1341  if (!missing(sigma)) {
1342    warning("Argument `sigma' is deprecated and has no effect")
1343  }
1344  if (!missing(initemp)) {
1345    warning("Argument `initemp' is deprecated and has no effect")
1346  }
1347  if (!missing(coolexp)) {
1348    warning("Argument `coolexp' is deprecated and has no effect")
1349  }
1350
1351  on.exit(.Call(C_R_igraph_finalizer) )
1352  # Function call
1353  if (dim == 2) {
1354    res <- .Call(C_R_igraph_layout_kamada_kawai, graph, coords, maxiter,
1355                 epsilon, kkconst, weights, minx, maxx, miny, maxy)
1356  } else {
1357    res <- .Call(C_R_igraph_layout_kamada_kawai_3d, graph, coords, maxiter,
1358                 epsilon, kkconst, weights, minx, maxx, miny, maxy, minz,
1359                 maxz)
1360  }
1361
1362  res
1363}
1364
1365
1366#' @rdname layout_with_kk
1367#' @param ... Passed to \code{layout_with_kk}.
1368#' @export
1369#'
1370with_kk <- function(...) layout_spec(layout_with_kk, ...)
1371
1372#' @export
1373#' @rdname layout.deprecated
1374
1375layout.kamada.kawai <- function(..., params = list()) {
1376  do_call(layout_with_kk, .args = c(list(...), params))
1377}
1378
1379## ----------------------------------------------------------------
1380
1381
1382#' Large Graph Layout
1383#'
1384#' A layout generator for larger graphs.
1385#'
1386#' \code{layout_with_lgl} is for large connected graphs, it is similar to the layout
1387#' generator of the Large Graph Layout software
1388#' (\url{http://lgl.sourceforge.net/}).
1389#'
1390#' @param graph The input graph
1391#' @param maxiter The maximum number of iterations to perform (150).
1392#' @param maxdelta The maximum change for a vertex during an iteration (the
1393#' number of vertices).
1394#' @param area The area of the surface on which the vertices are placed (square
1395#' of the number of vertices).
1396#' @param coolexp The cooling exponent of the simulated annealing (1.5).
1397#' @param repulserad Cancellation radius for the repulsion (the \code{area}
1398#' times the number of vertices).
1399#' @param cellsize The size of the cells for the grid. When calculating the
1400#' repulsion forces between vertices only vertices in the same or neighboring
1401#' grid cells are taken into account (the fourth root of the number of
1402#' \code{area}.
1403#' @param root The id of the vertex to place at the middle of the layout. The
1404#' default value is -1 which means that a random vertex is selected.
1405#' @return A numeric matrix with two columns and as many rows as vertices.
1406#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
1407#' @keywords graphs
1408#' @export
1409#' @family graph layouts
1410
1411layout_with_lgl <- function(graph, maxiter=150, maxdelta=vcount(graph),
1412                       area=vcount(graph)^2, coolexp=1.5,
1413                       repulserad=area * vcount(graph),
1414                       cellsize=sqrt(sqrt(area)), root=NULL) {
1415
1416  if (!is_igraph(graph)) {
1417    stop("Not a graph object")
1418  }
1419  if (is.null(root)) {
1420    root <- -1
1421  } else {
1422    root <- as.igraph.vs(graph, root)-1
1423  }
1424
1425  on.exit(.Call(C_R_igraph_finalizer) )
1426  .Call(C_R_igraph_layout_lgl, graph, as.double(maxiter),
1427        as.double(maxdelta), as.double(area), as.double(coolexp),
1428        as.double(repulserad), as.double(cellsize), root)
1429}
1430
1431
1432#' @rdname layout_with_lgl
1433#' @param ... Passed to \code{layout_with_lgl}.
1434#' @export
1435
1436with_lgl <- function(...) layout_spec(layout_with_lgl, ...)
1437
1438#' @export
1439#' @rdname layout.deprecated
1440
1441layout.lgl <- function(..., params = list()) {
1442  do_call(layout_with_lgl, .args = c(list(...), params))
1443}
1444
1445## ----------------------------------------------------------------
1446
1447
1448
1449#' Graph layout by multidimensional scaling
1450#'
1451#' Multidimensional scaling of some distance matrix defined on the vertices of
1452#' a graph.
1453#'
1454#' \code{layout_with_mds} uses metric multidimensional scaling for generating the
1455#' coordinates. Multidimensional scaling aims to place points from a higher
1456#' dimensional space in a (typically) 2 dimensional plane, so that the distance
1457#' between the points are kept as much as this is possible.
1458#'
1459#' By default igraph uses the shortest path matrix as the distances between the
1460#' nodes, but the user can override this via the \code{dist} argument.
1461#'
1462#' This function generates the layout separately for each graph component and
1463#' then merges them via \code{\link{merge_coords}}.
1464#'
1465#' @aliases layout.mds
1466#' @param graph The input graph.
1467#' @param dist The distance matrix for the multidimensional scaling.  If
1468#' \code{NULL} (the default), then the unweighted shortest path matrix is used.
1469#' @param dim \code{layout_with_mds} supports dimensions up to the number of nodes
1470#' minus one, but only if the graph is connected; for unconnected graphs, the
1471#' only possible values is 2. This is because \code{merge_coords} only works in
1472#' 2D.
1473#' @param options This is currently ignored, as ARPACK is not used any more for
1474#' solving the eigenproblem
1475#' @return A numeric matrix with \code{dim} columns.
1476#' @author Tamas Nepusz \email{ntamas@@gmail.com} and Gabor Csardi
1477#' \email{csardi.gabor@@gmail.com}
1478#' @seealso \code{\link{layout}}, \code{\link{plot.igraph}}
1479#' @references Cox, T. F. and Cox, M. A. A. (2001) \emph{Multidimensional
1480#' Scaling}.  Second edition. Chapman and Hall.
1481#' @export
1482#' @family graph layouts
1483#' @keywords graphs
1484#' @examples
1485#'
1486#' g <- sample_gnp(100, 2/100)
1487#' l <- layout_with_mds(g)
1488#' plot(g, layout=l, vertex.label=NA, vertex.size=3)
1489
1490layout_with_mds <- function(graph, dist=NULL, dim=2,
1491                       options=arpack_defaults) {
1492
1493  # Argument checks
1494  if (!is_igraph(graph)) { stop("Not a graph object") }
1495  if (!is.null(dist)) dist <- structure(as.double(dist), dim=dim(dist))
1496  dim <- as.integer(dim)
1497
1498  on.exit(.Call(C_R_igraph_finalizer) )
1499  # Function call
1500  res <- .Call(C_R_igraph_layout_mds, graph, dist, dim)
1501
1502  res
1503}
1504
1505
1506#' @rdname layout_with_mds
1507#' @param ... Passed to \code{layout_with_mds}.
1508#' @export
1509
1510with_mds <- function(...) layout_spec(layout_with_mds, ...)
1511
1512
1513## ----------------------------------------------------------------
1514
1515
1516#' The Sugiyama graph layout generator
1517#'
1518#' Sugiyama layout algorithm for layered directed acyclic graphs. The algorithm
1519#' minimized edge crossings.
1520#'
1521#' This layout algorithm is designed for directed acyclic graphs where each
1522#' vertex is assigned to a layer. Layers are indexed from zero, and vertices of
1523#' the same layer will be placed on the same horizontal line. The X coordinates
1524#' of vertices within each layer are decided by the heuristic proposed by
1525#' Sugiyama et al. to minimize edge crossings.
1526#'
1527#' You can also try to lay out undirected graphs, graphs containing cycles, or
1528#' graphs without an a priori layered assignment with this algorithm. igraph
1529#' will try to eliminate cycles and assign vertices to layers, but there is no
1530#' guarantee on the quality of the layout in such cases.
1531#'
1532#' The Sugiyama layout may introduce \dQuote{bends} on the edges in order to
1533#' obtain a visually more pleasing layout. This is achieved by adding dummy
1534#' nodes to edges spanning more than one layer. The resulting layout assigns
1535#' coordinates not only to the nodes of the original graph but also to the
1536#' dummy nodes. The layout algorithm will also return the extended graph with
1537#' the dummy nodes.
1538#'
1539#' For more details, see the reference below.
1540#'
1541#' @aliases layout.sugiyama
1542#' @param graph The input graph.
1543#' @param layers A numeric vector or \code{NULL}. If not \code{NULL}, then it
1544#' should specify the layer index of the vertices. Layers are numbered from
1545#' one. If \code{NULL}, then igraph calculates the layers automatically.
1546#' @param hgap Real scalar, the minimum horizontal gap between vertices in the
1547#' same layer.
1548#' @param vgap Real scalar, the distance between layers.
1549#' @param maxiter Integer scalar, the maximum number of iterations in the
1550#' crossing minimization stage. 100 is a reasonable default; if you feel that
1551#' you have too many edge crossings, increase this.
1552#' @param weights Optional edge weight vector. If \code{NULL}, then the
1553#' 'weight' edge attribute is used, if there is one. Supply \code{NA} here and
1554#' igraph ignores the edge weights. These are used only if the graph
1555#' contains cycles; igraph will tend to reverse edges with smaller weights
1556#' when breaking the cycles.
1557#' @param attributes Which graph/vertex/edge attributes to keep in the extended
1558#' graph. \sQuote{default} keeps the \sQuote{size}, \sQuote{size2},
1559#' \sQuote{shape}, \sQuote{label} and \sQuote{color} vertex attributes and the
1560#' \sQuote{arrow.mode} and \sQuote{arrow.size} edge attributes. \sQuote{all}
1561#' keep all graph, vertex and edge attributes, \sQuote{none} keeps none of
1562#' them.
1563#' @return A list with the components: \item{layout}{The layout, a two-column
1564#' matrix, for the original graph vertices.} \item{layout.dummy}{The layout for
1565#' the dummy vertices, a two column matrix.} \item{extd_graph}{The original
1566#' graph, extended with dummy vertices.  The \sQuote{dummy} vertex attribute is
1567#' set on this graph, it is a logical attributes, and it tells you whether the
1568#' vertex is a dummy vertex. The \sQuote{layout} graph attribute is also set,
1569#' and it is the layout matrix for all (original and dummy) vertices.}
1570#' @author Tamas Nepusz \email{ntamas@@gmail.com}
1571#' @references K. Sugiyama, S. Tagawa and M. Toda, "Methods for Visual
1572#' Understanding of Hierarchical Systems". IEEE Transactions on Systems, Man
1573#' and Cybernetics 11(2):109-125, 1981.
1574#' @export
1575#' @importFrom utils head
1576#' @family graph layouts
1577#' @keywords graphs
1578#' @examples
1579#'
1580#' ## Data taken from http://tehnick-8.narod.ru/dc_clients/
1581#' DC <- graph_from_literal("DC++" -+
1582#'                 "LinuxDC++":"BCDC++":"EiskaltDC++":"StrongDC++":"DiCe!++",
1583#'                 "LinuxDC++" -+ "FreeDC++", "BCDC++" -+ "StrongDC++",
1584#'                 "FreeDC++" -+ "BMDC++":"EiskaltDC++",
1585#'                 "StrongDC++" -+ "AirDC++":"zK++":"ApexDC++":"TkDC++",
1586#'                 "StrongDC++" -+ "StrongDC++ SQLite":"RSX++",
1587#'                 "ApexDC++" -+ "FlylinkDC++ ver <= 4xx",
1588#'                 "ApexDC++" -+ "ApexDC++ Speed-Mod":"DiCe!++",
1589#'                 "StrongDC++ SQLite" -+ "FlylinkDC++ ver >= 5xx",
1590#'                 "ApexDC++ Speed-Mod" -+ "FlylinkDC++ ver <= 4xx",
1591#'                 "ApexDC++ Speed-Mod" -+ "GreylinkDC++",
1592#'                 "FlylinkDC++ ver <= 4xx" -+ "FlylinkDC++ ver >= 5xx",
1593#'                 "FlylinkDC++ ver <= 4xx" -+ AvaLink,
1594#'                 "GreylinkDC++" -+ AvaLink:"RayLinkDC++":"SparkDC++":PeLink)
1595#'
1596#' ## Use edge types
1597#' E(DC)$lty <- 1
1598#' E(DC)["BCDC++" %->% "StrongDC++"]$lty <- 2
1599#' E(DC)["FreeDC++" %->% "EiskaltDC++"]$lty <- 2
1600#' E(DC)["ApexDC++" %->% "FlylinkDC++ ver <= 4xx"]$lty <- 2
1601#' E(DC)["ApexDC++" %->% "DiCe!++"]$lty <- 2
1602#' E(DC)["StrongDC++ SQLite" %->% "FlylinkDC++ ver >= 5xx"]$lty <- 2
1603#' E(DC)["GreylinkDC++" %->% "AvaLink"]$lty <- 2
1604#'
1605#' ## Layers, as on the plot
1606#' layers <- list(c("DC++"),
1607#'                c("LinuxDC++", "BCDC++"),
1608#'                c("FreeDC++", "StrongDC++"),
1609#'                c("BMDC++", "EiskaltDC++", "AirDC++", "zK++", "ApexDC++",
1610#'                  "TkDC++", "RSX++"),
1611#'                c("StrongDC++ SQLite", "ApexDC++ Speed-Mod", "DiCe!++"),
1612#'                c("FlylinkDC++ ver <= 4xx", "GreylinkDC++"),
1613#'                c("FlylinkDC++ ver >= 5xx", "AvaLink", "RayLinkDC++",
1614#'                  "SparkDC++", "PeLink"))
1615#'
1616#' ## Check that we have all nodes
1617#' all(sort(unlist(layers)) == sort(V(DC)$name))
1618#'
1619#' ## Add some graphical parameters
1620#' V(DC)$color <- "white"
1621#' V(DC)$shape <- "rectangle"
1622#' V(DC)$size <- 20
1623#' V(DC)$size2 <- 10
1624#' V(DC)$label <- lapply(V(DC)$name, function(x)
1625#'                       paste(strwrap(x, 12), collapse="\n"))
1626#' E(DC)$arrow.size <- 0.5
1627#'
1628#' ## Create a similar layout using the predefined layers
1629#' lay1 <-  layout_with_sugiyama(DC, layers=apply(sapply(layers,
1630#'                         function(x) V(DC)$name %in% x), 1, which))
1631#'
1632#' ## Simple plot, not very nice
1633#' par(mar=rep(.1, 4))
1634#' plot(DC, layout=lay1$layout, vertex.label.cex=0.5)
1635#'
1636#' ## Sugiyama plot
1637#' plot(lay1$extd_graph, vertex.label.cex=0.5)
1638#'
1639#' ## The same with automatic layer calculation
1640#' ## Keep vertex/edge attributes in the extended graph
1641#' lay2 <-  layout_with_sugiyama(DC, attributes="all")
1642#' plot(lay2$extd_graph, vertex.label.cex=0.5)
1643#'
1644#' ## Another example, from the following paper:
1645#' ## Markus Eiglsperger, Martin Siebenhaller, Michael Kaufmann:
1646#' ## An Efficient Implementation of Sugiyama's Algorithm for
1647#' ## Layered Graph Drawing, Journal of Graph Algorithms and
1648#' ## Applications 9, 305--325 (2005).
1649#'
1650#' ex <- graph_from_literal( 0 -+ 29: 6: 5:20: 4,
1651#'                  1 -+ 12,
1652#'                  2 -+ 23: 8,
1653#'                  3 -+  4,
1654#'                  4,
1655#'                  5 -+  2:10:14:26: 4: 3,
1656#'                  6 -+  9:29:25:21:13,
1657#'                  7,
1658#'                  8 -+ 20:16,
1659#'                  9 -+ 28: 4,
1660#'                 10 -+ 27,
1661#'                 11 -+  9:16,
1662#'                 12 -+  9:19,
1663#'                 13 -+ 20,
1664#'                 14 -+ 10,
1665#'                 15 -+ 16:27,
1666#'                 16 -+ 27,
1667#'                 17 -+  3,
1668#'                 18 -+ 13,
1669#'                 19 -+  9,
1670#'                 20 -+  4,
1671#'                 21 -+ 22,
1672#'                 22 -+  8: 9,
1673#'                 23 -+  9:24,
1674#'                 24 -+ 12:15:28,
1675#'                 25 -+ 11,
1676#'                 26 -+ 18,
1677#'                 27 -+ 13:19,
1678#'                 28 -+  7,
1679#'                 29 -+ 25                    )
1680#'
1681#' layers <- list( 0, c(5, 17), c(2, 14, 26, 3), c(23, 10, 18), c(1, 24),
1682#'                 12, 6, c(29,21), c(25,22), c(11,8,15), 16, 27, c(13,19),
1683#'                 c(9, 20), c(4, 28), 7 )
1684#'
1685#' layex <-  layout_with_sugiyama(ex, layers=apply(sapply(layers,
1686#'                         function(x) V(ex)$name %in% as.character(x)),
1687#'                         1, which))
1688#'
1689#' origvert <- c(rep(TRUE, vcount(ex)), rep(FALSE, nrow(layex$layout.dummy)))
1690#' realedge <- as_edgelist(layex$extd_graph)[,2] <= vcount(ex)
1691#' plot(layex$extd_graph, vertex.label.cex=0.5,
1692#'      edge.arrow.size=.5,
1693#'      vertex.size=ifelse(origvert, 5, 0),
1694#'      vertex.shape=ifelse(origvert, "square", "none"),
1695#'      vertex.label=ifelse(origvert, V(ex)$name, ""),
1696#'      edge.arrow.mode=ifelse(realedge, 2, 0))
1697#'
1698 layout_with_sugiyama <- function(graph, layers=NULL, hgap=1, vgap=1,
1699                            maxiter=100, weights=NULL,
1700                            attributes=c("default", "all", "none")) {
1701  # Argument checks
1702  if (!is_igraph(graph)) { stop("Not a graph object") }
1703  if (!is.null(layers)) layers <- as.numeric(layers)-1
1704  hgap <- as.numeric(hgap)
1705  vgap <- as.numeric(vgap)
1706  maxiter <- as.integer(maxiter)
1707  if (is.null(weights) && "weight" %in% edge_attr_names(graph)) {
1708    weights <- E(graph)$weight
1709  }
1710  if (!is.null(weights) && any(!is.na(weights))) {
1711    weights <- as.numeric(weights)
1712  } else {
1713    weights <- NULL
1714  }
1715  attributes <- igraph.match.arg(attributes)
1716
1717  on.exit(.Call(C_R_igraph_finalizer) )
1718  # Function call
1719  res <- .Call(C_R_igraph_layout_sugiyama, graph, layers, hgap,
1720               vgap, maxiter, weights)
1721
1722  # Flip the y coordinates, more natural this way
1723  res$res[,2] <- max(res$res[,2]) - res$res[,2] + 1
1724
1725  # Separate real and dummy vertices
1726  vc <- vcount(graph)
1727  if (nrow(res$res)==vc) {
1728    res$layout <- res$res
1729    res$layout.dummy <- matrix(NA_real_, nrow=0, ncol=2)
1730  } else {
1731    res$layout <- res$res[seq_len(vc),]
1732    res$layout.dummy <- res$res[(vc+1):nrow(res$res),]
1733  }
1734
1735  # Add some attributes to the extended graph
1736  E(res$extd_graph)$orig <- res$extd_to_orig_eids
1737  res$extd_to_orig_eids <- NULL
1738
1739  res$extd_graph <- set_vertex_attr(res$extd_graph, "dummy",
1740                                         value=c(rep(FALSE, vc),
1741                                           rep(TRUE, nrow(res$res)-vc)))
1742
1743  res$extd_graph$layout <- rbind(res$layout, res$layout.dummy)
1744
1745  if (attributes=="default" || attributes=="all") {
1746    if ("size" %in% vertex_attr_names(graph)) {
1747      V(res$extd_graph)$size <- 0
1748      V(res$extd_graph)$size[ !V(res$extd_graph)$dummy ] <- V(graph)$size
1749    }
1750    if ("size2" %in% vertex_attr_names(graph)) {
1751      V(res$extd_graph)$size2 <- 0
1752      V(res$extd_graph)$size2[ !V(res$extd_graph)$dummy ] <- V(graph)$size2
1753    }
1754    if ("shape" %in% vertex_attr_names(graph)) {
1755      V(res$extd_graph)$shape <- "none"
1756      V(res$extd_graph)$shape[ !V(res$extd_graph)$dummy ] <- V(graph)$shape
1757    }
1758    if ("label" %in% vertex_attr_names(graph)) {
1759      V(res$extd_graph)$label <- ""
1760      V(res$extd_graph)$label[ !V(res$extd_graph)$dummy ] <- V(graph)$label
1761    }
1762    if ("color" %in% vertex_attr_names(graph)) {
1763      V(res$extd_graph)$color <- head(V(graph)$color, 1)
1764      V(res$extd_graph)$color[ !V(res$extd_graph)$dummy ] <- V(graph)$color
1765    }
1766    eetar <- as_edgelist(res$extd_graph, names=FALSE)[,2]
1767    E(res$extd_graph)$arrow.mode <- 0
1768    if ("arrow.mode" %in% edge_attr_names(graph)) {
1769      E(res$extd_graph)$arrow.mode[ eetar <= vc ] <- E(graph)$arrow.mode
1770    } else {
1771      E(res$extd_graph)$arrow.mode[ eetar <= vc ] <- is_directed(graph) * 2
1772    }
1773    if ("arrow.size" %in% edge_attr_names(graph)) {
1774      E(res$extd_graph)$arrow.size <- 0
1775      E(res$extd_graph)$arrow.size[ eetar <= vc ] <- E(graph)$arrow.size
1776    }
1777  }
1778
1779  if (attributes=="all") {
1780    gatt <- setdiff(graph_attr_names(graph), "layout")
1781    vatt <- setdiff(vertex_attr_names(graph),
1782                    c("size", "size2", "shape", "label", "color"))
1783    eatt <- setdiff(edge_attr_names(graph),
1784                    c("arrow.mode", "arrow.size"))
1785    for (ga in gatt) {
1786      res$extd_graph <- set_graph_attr(res$extd_graph, ga,
1787                                            graph_attr(graph, ga))
1788    }
1789    for (va in vatt) {
1790      notdummy <- which(!V(res$extd_graph)$dummy)
1791      res$extd_graph <- set_vertex_attr(res$extd_graph, va,
1792                                             notdummy,
1793                                             vertex_attr(graph, va))
1794    }
1795    for (ea in eatt) {
1796      eanew <- edge_attr(graph, ea)[E(res$extd_graph)$orig]
1797      res$extd_graph <- set_edge_attr(res$extd_graph, ea, value=eanew)
1798    }
1799  }
1800
1801  res$res <- NULL
1802  res
1803}
1804
1805
1806#' @rdname layout_with_sugiyama
1807#' @param ... Passed to \code{layout_with_sugiyama}.
1808#' @export
1809
1810with_sugiyama <- function(...) layout_spec(layout_with_sugiyama, ...)
1811
1812
1813## ----------------------------------------------------------------
1814
1815
1816#' Merging graph layouts
1817#'
1818#' Place several graphs on the same layout
1819#'
1820#' \code{merge_coords} takes a list of graphs and a list of coordinates and
1821#' places the graphs in a common layout. The method to use is chosen via the
1822#' \code{method} parameter, although right now only the \code{dla} method is
1823#' implemented.
1824#'
1825#' The \code{dla} method covers the graph with circles.  Then it sorts the
1826#' graphs based on the number of vertices first and places the largest graph at
1827#' the center of the layout. Then the other graphs are placed in decreasing
1828#' order via a DLA (diffision limited aggregation) algorithm: the graph is
1829#' placed randomly on a circle far away from the center and a random walk is
1830#' conducted until the graph walks into the larger graphs already placed or
1831#' walks too far from the center of the layout.
1832#'
1833#' The \code{layout_components} function disassembles the graph first into
1834#' maximal connected components and calls the supplied \code{layout} function
1835#' for each component separately. Finally it merges the layouts via calling
1836#' \code{merge_coords}.
1837#'
1838#' @aliases layout.merge piecewise.layout
1839#' @param graphs A list of graph objects.
1840#' @param layouts A list of two-column matrices.
1841#' @param method Character constant giving the method to use. Right now only
1842#' \code{dla} is implemented.
1843#' @param layout A function object, the layout function to use.
1844#' @param \dots Additional arguments to pass to the \code{layout} layout
1845#' function.
1846#' @return A matrix with two columns and as many lines as the total number of
1847#' vertices in the graphs.
1848#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
1849#' @seealso \code{\link{plot.igraph}}, \code{\link{tkplot}},
1850#' \code{\link{layout}}, \code{\link{disjoint_union}}
1851#' @export
1852#' @family graph layouts
1853#' @keywords graphs
1854#' @examples
1855#'
1856#' # create 20 scale-free graphs and place them in a common layout
1857#' graphs <- lapply(sample(5:20, 20, replace=TRUE),
1858#'           barabasi.game, directed=FALSE)
1859#' layouts <- lapply(graphs, layout_with_kk)
1860#' lay <- merge_coords(graphs, layouts)
1861#' g <- disjoint_union(graphs)
1862#' \dontrun{plot(g, layout=lay, vertex.size=3, labels=NA, edge.color="black")}
1863
1864merge_coords <- function(graphs, layouts, method="dla") {
1865
1866  if (!all(sapply(graphs, is_igraph))) {
1867    stop("Not a graph object")
1868  }
1869  if (method == "dla") {
1870    on.exit(.Call(C_R_igraph_finalizer) )
1871    res <- .Call(C_R_igraph_layout_merge_dla,
1872                 graphs, layouts)
1873  } else {
1874    stop("Invalid `method'.")
1875  }
1876  res
1877}
1878
1879
1880
1881#' Normalize coordinates for plotting graphs
1882#'
1883#' Rescale coordinates linearly to be within given bounds.
1884#'
1885#' \code{norm_coords} normalizes a layout, it linearly transforms each
1886#' coordinate separately to fit into the given limits.
1887#'
1888#' @aliases layout.norm
1889#' @param layout A matrix with two or three columns, the layout to normalize.
1890#' @param xmin,xmax The limits for the first coordinate, if one of them or both
1891#' are \code{NULL} then no normalization is performed along this direction.
1892#' @param ymin,ymax The limits for the second coordinate, if one of them or
1893#' both are \code{NULL} then no normalization is performed along this
1894#' direction.
1895#' @param zmin,zmax The limits for the third coordinate, if one of them or both
1896#' are \code{NULL} then no normalization is performed along this direction.
1897#' @return A numeric matrix with at the same dimension as \code{layout}.
1898#' @author Gabor Csardi \email{csardi.gabor@@gmail.com}
1899#' @export
1900#' @family graph layouts
1901#' @keywords graphs
1902
1903norm_coords <- function(layout, xmin=-1, xmax=1, ymin=-1, ymax=1,
1904                          zmin=-1, zmax=1) {
1905
1906  if (!is.matrix(layout)) {
1907    stop("`layout' must be a matrix")
1908  }
1909  if (ncol(layout) != 2 && ncol(layout) != 3) {
1910    stop("`layout' should have 2 or three columns")
1911  }
1912
1913  if (!is.null(xmin) && !is.null(xmax)) {
1914    layout[,1] <- .layout.norm.col(layout[,1], xmin, xmax)
1915  }
1916
1917  if (!is.null(ymin) && !is.null(ymax)) {
1918    layout[,2] <- .layout.norm.col(layout[,2], ymin, ymax)
1919  }
1920
1921  if (ncol(layout)==3 && !is.null(zmin) && !is.null(zmax)) {
1922    layout[,3] <- .layout.norm.col(layout[,3], zmin, zmax)
1923  }
1924
1925  layout
1926}
1927
1928.layout.norm.col <- function(v, min, max) {
1929
1930  vr <- range(v)
1931  if (vr[1]==vr[2]) {
1932    fac <- 1
1933  } else {
1934    fac <- (max-min)/(vr[2]-vr[1])
1935  }
1936
1937  (v-vr[1]) * fac + min
1938}
1939
1940#' @rdname merge_coords
1941#' @aliases piecewise.layout
1942#' @param graph The input graph.
1943#' @export
1944
1945layout_components <- function(graph, layout=layout_with_kk, ...) {
1946
1947  if (!is_igraph(graph)) {
1948    stop("Not a graph object")
1949  }
1950
1951  V(graph)$id <- seq(vcount(graph))
1952  gl <- decompose(graph)
1953  ll <- lapply(gl, layout, ...)
1954
1955  l <- merge_coords(gl, ll)
1956  l[ unlist(sapply(gl, vertex_attr, "id")), ] <- l[]
1957  l
1958}
1959
1960#' Spring layout, this was removed from igraph
1961#'
1962#' Now it calls the Fruchterman-Reingold layout, with a warning.
1963#'
1964#' @param graph Input graph.
1965#' @param ... Extra arguments are ignored.
1966#' @return Layout coordinates, a two column matrix.
1967#'
1968#' @export
1969
1970layout.spring <- function(graph, ...) {
1971  warning("Spring layout was removed, we use Fruchterman-Reingold instead.")
1972  layout_with_fr(graph)
1973}
1974
1975#' SVD layout, this was removed from igraph
1976#'
1977#' Now it calls the Fruchterman-Reingold layout, with a warning.
1978#'
1979#' @param graph Input graph.
1980#' @param ... Extra arguments are ignored.
1981#' @return Layout coordinates, a two column matrix.
1982#'
1983#' @export
1984
1985layout.svd <- function(graph, ...) {
1986  warning("SVD layout was removed, we use Fruchterman-Reingold instead.")
1987  layout_with_fr(graph)
1988}
1989
1990#' Grid Fruchterman-Reingold layout, this was removed from igraph
1991#'
1992#' Now it calls the Fruchterman-Reingold layout, with a warning.
1993#'
1994#' @param graph Input graph.
1995#' @param ... Extra arguments are ignored.
1996#' @return Layout coordinates, a two column matrix.
1997#'
1998#' @export
1999
2000layout.fruchterman.reingold.grid <- function(graph, ...) {
2001  warning("Grid Fruchterman-Reingold layout was removed,\n",
2002          "we use Fruchterman-Reingold instead.")
2003  layout_with_fr(graph)
2004}
2005