igraph-help
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[igraph] help with graph.union.by.name


From: Umberto Medicamento
Subject: [igraph] help with graph.union.by.name
Date: Wed, 05 Nov 2014 16:14:01 +0100
User-agent: Internet Messaging Program (IMP) H5 (6.2.2)

Hi all,
I was applying the function graph.union.by.name over a list of weighted graphs. The function I used is as follows (it also provides for intersection and other operations).
Unfortunately, I cannot recall where I found it.

After uniting the first two graphs, I compared the result obtained both using the graph.union.by.name in its weighted and unweighted version.

With the weighted form of the function I've got a (third) graph with 99 nodes and 983 edges, while with its unweighted form I've got a (third) graph with 99 nodes and 638 edges.

Anybody can help me to understand why?

Thanks a lot, Umberto M.


# READ: for weighted graphs change get.edges.as.data.frame = function(graph, keep.attributes=FALSE
# to:
# get.edges.as.data.frame = function(graph, keep.attributes=TRUE)

safer.merge = function(
  x, y, by = intersect(names(x), names(y)),
  by.x = by, by.y = by, all = FALSE, all.x = all, all.y = all,
  suffixes = c(".x",".y"), incomparables = NULL,
  indicate.origin=FALSE, allow.duplicates=FALSE,
  allow.duplicates.x=allow.duplicates, allow.duplicates.y=allow.duplicates,
  ...)
{
  if ( !allow.duplicates.x & (sum(duplicated(x[,by.x]))!=0) )
  {
stop("safer.merge: Duplicates found in x, but allow.duplicates.x is FALSE" )
  }
  if ( !allow.duplicates.y & (sum(duplicated(y[,by.y]))!=0) )
  {
stop("safer.merge: Duplicates found in y, but allow.duplicates.y is FALSE" )
  }
  stopifnot( sum(is.na(x[,by.x])) == 0 )
  stopifnot( sum(is.na(y[,by.y])) == 0 )

  if ( indicate.origin )
  {
    stopifnot( !("was.in" %in% names(x) ) )
    stopifnot( !("was.in" %in% names(y) ) )
    x$was.in=rep(TRUE,nrow(x))
    y$was.in=rep(TRUE,nrow(y))
  }

  result = merge(x, y, by=by,
                 by.x=by.x, by.y=by.y, all=all, all.x=all.x, all.y=all.y,
sort=TRUE, suffixes=suffixes, incomparables=incomparables, ...)

  if ( indicate.origin & nrow(result) > 0 )
  {
    was.in.x = paste0("was.in", suffixes[1])
    was.in.y = paste0("was.in", suffixes[2])
    result[ is.na(result[,was.in.x]) , was.in.x] = FALSE
    result[ is.na(result[,was.in.y]) , was.in.y] = FALSE
  }

  return(result)
}

# Return graph vertices as a data.frame.
# If keep.attributes == TRUE, the data.frame contains all vertex attributes.
get.vertices.as.data.frame = function(graph, keep.attributes=TRUE)
{
stopifnot( length(V(graph)$name) == length(unique(V(graph)$name))) # Vertex names must be unique
  if ( is.null(V(graph)$name) ) return(data.frame(V=character()))
  d = data.frame(V=V(graph)$name)
  if ( keep.attributes )
  {
    # Bind attributes if requested
    attr.names = list.vertex.attributes(graph)
    d.a = as.data.frame(lapply( attr.names,
function(attr, g){get.vertex.attribute(g,attr)},
                                graph))
    names(d.a) = attr.names
    d = cbind(d,d.a)
  }
  return(d)
}

# Return graph edges as a mergable data.frame
# If the graph is undirected, the result will have all V1 <= V2
# If keep.attributes == TRUE, the data.frame contains all edge attributes.
get.edges.as.data.frame = function(graph, keep.attributes=TRUE)
{
stopifnot( length(V(graph)$name) == length(unique(V(graph)$name))) # Vertex names must be unique
  m = get.edgelist(graph)
  if ( !is.directed(graph) )
  {
    ix.rev        = m[,1] > m[,2]       # Choose which pairs to switch
    m[ix.rev,1:2] = m[ix.rev,2:1]       # Switch
  }
  d = as.data.frame(m)
  if ( keep.attributes )
  {
    # Bind attributes if requested
    attr.names = list.edge.attributes(graph)
    d.a = as.data.frame(lapply( attr.names,
                                function(attr, g){get.edge.attribute(g,attr)},
                                graph))
    names(d.a) = attr.names
    d = cbind(d,d.a)
  }
  return(d)
}

check.graphs.for.set.operations = function(g1, g2) {
  if(is.directed(g1) & !is.directed(g2) ||
       !is.directed(g1) & is.directed(g2))
    stop("g1 and g2 must be both directed or both undirected")
  if(vcount(g1) > 0 & is.null(V(g1)$name))
    stop("g1 must have a vertex name attribute")
  if(vcount(g2) > 0 & is.null(V(g2)$name))
    stop("g2 must have a vertex name attribute")
}

# Create an intersection of two graphs.
# This function correctly intersects the graphs based
# on the name attributes, such that:
#   Any vertex that is in g1 and g2 is in the result.
#   Any edge that is in g1 and g2 is in the result.
# This function preserves some attributes, but not all.
graph.intersection.by.name = function(g1, g2,
                                      keep.x.vertices          = FALSE,
                                      keep.x.vertex.attributes = FALSE,
                                      keep.x.edge.attributes   = FALSE)
{
  check.graphs.for.set.operations(g1, g2)

  # Construct data.frames of nodes and edges
dv1 = get.vertices.as.data.frame(g1, keep.attributes=keep.x.vertex.attributes)
  dv2 = get.vertices.as.data.frame(g2)
  de1 = get.edges.as.data.frame(g1, keep.attributes=keep.x.edge.attributes)
  de2 = get.edges.as.data.frame(g2)

  # Merge data.frames and construct result
  if ( keep.x.vertices )
    dv = dv1
  else
    dv = safer.merge(dv1, dv2)
  de = safer.merge(de1, de2)
  g  = graph.data.frame(de, directed=is.directed(g1), vertices=dv)
  return(g)
}

# Create union of two graphs.
# This function correctly unions the graphs based
# on the name attributes, such that:
#   Any vertex that is in g1 or g2 is in the result.
#   Any edge that is in g1 or g2 is in the result.
# However, this function does NOT preserve other attributes.
graph.union.by.name = function(g1, g2)
{
  check.graphs.for.set.operations(g1, g2)

  # Construct data.frames of nodes and edges
  dv1 = get.vertices.as.data.frame(g1)
  dv2 = get.vertices.as.data.frame(g2)
  de1 = get.edges.as.data.frame(g1)
  de2 = get.edges.as.data.frame(g2)

  # Merge data.frames and construct result
  dv = safer.merge(dv1, dv2, all=TRUE)
  de = safer.merge(de1, de2, all=TRUE)
  g = graph.data.frame(de, directed=is.directed(g1), vertices=dv)
  return(g)
}

# Create difference of two graphs.
# This function correctly diffs the graphs based
# on the name attributes. Note that this difference applies
# only to the edges, not the vertices, so that:
#   Any vertex that is in g1 is in the result.
#   Any edge that is in g1 but not in g2 is in the result.
# However, this function does NOT preserve other attributes.
graph.difference.by.name = function(g1, g2,
                                    keep.x.vertex.attributes = FALSE,
                                    keep.x.edge.attributes   = FALSE)
{
  check.graphs.for.set.operations(g1, g2)

  # Construct data.frames of nodes and edges
dv = get.vertices.as.data.frame(g1, keep.attributes=keep.x.vertex.attributes)
  de1 = get.edges.as.data.frame(g1, keep.attributes=keep.x.edge.attributes)
  de2 = get.edges.as.data.frame(g2)

  # Merge data.frames and construct result
  de = safer.merge(de1, de2, all=TRUE, indicate.origin=TRUE) # All edges
  if( nrow(de) > 0 ) {
de = de[ (de$was.in.x & !de$was.in.y) , # Remove g2 edges setdiff(names(de),c("was.in.x","was.in.y")) ] # Keep attributes from g1 g = graph.data.frame(de, directed=is.directed(g1), vertices=dv) # The new graph
  } else {
    g = delete.edges(g1, E(g1))
  }
  return(g)
}


# Test/demonstration code
if (FALSE)
{

  # Load library and set parameters for better printing
  library(igraph)
  igraph.options(print.vertex.attributes=TRUE)
  igraph.options(print.edge.attributes=TRUE)

  # Define input graphs
  g1 <- graph.formula(a-b-c)
  V(g1)$v.attr=c(1,2,3)
  E(g1)$e.attr=c(5,7)
  g2 <- graph.formula(b-c-d)

  # Test the functions
  graph.intersection.by.name(g1,g2) # Vertices are intersected as well
  graph.union.by.name(g1,g2)        # Vertices are unioned as well
  graph.difference.by.name(g1,g2)   # Vertices from x (g1) are used

  # graph.intersection.by.name() has some extra parameters
  graph.intersection.by.name(g1,g2,
keep.x.vertices = TRUE) # Keep all x vertices (only intersect edges)

  graph.intersection.by.name(g1,g2,
keep.x.vertices = FALSE, # Keep all x vertices (only intersect edges) keep.x.vertex.attributes = TRUE, # Don't throw away V(g1) attributes keep.x.edge.attributes = TRUE) # Don't throw away E(g1) attributes

  # graph.difference.by.name() has some extra parameters
  graph.difference.by.name(g1,g2,
keep.x.vertex.attributes = TRUE, # Don't throw away V(g1) attributes keep.x.edge.attributes = TRUE) # Don't throw away E(g1) attributes

}


--
Dr. Agr. Umberto Medicamento
PhD, MoS
address@hidden
mob. +39.320.83.68.670
skype umberto7755




reply via email to

[Prev in Thread] Current Thread [Next in Thread]