Skip to content

Commit

Permalink
Merge pull request #111 from clhunsen/claus-updates
Browse files Browse the repository at this point in the history
Various minor and major fixes and adjustments

Reviewed-by: Thomas Bock <[email protected]>
  • Loading branch information
bockthom authored Mar 26, 2018
2 parents 73e9caf + e1a339d commit f07ee11
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 82 deletions.
16 changes: 16 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
# codeface-extraction-r - Changelog


## Unversioned

### Added
- ...

### Changed/Improved
- Vertex and edge types (attribute `"type"`) are now a character string (e.g., "Author" or "Unipartite") (#110, 3ca6ed99cf377200adb94a4b27ed1ea7d3a6981a)
- Default plotting layout is now `igraph::layout.kamada.kawai` (#109, 909965453c47c26c902612cb0c9aa16a5b56746a)
- Remove parameter 'color.attr' from 'motifs.search.in.network' (d33f6863aaf05ae1a8acf7f5667784713796b734)
- Fix and clean-up of both the plotting and the motif modules (3ca6ed99cf377200adb94a4b27ed1ea7d3a6981a, consequence of #110)

### Fixed
- Probably fixed segfaults during plotting by changing the default layout (see above and issue #109)
- Fix gray-scale plotting of networks (730cc544edbb30ea3aa89a91e123e74b18a942c6)


## 3.1.1

### Changed/Improved
Expand Down
6 changes: 3 additions & 3 deletions showcase.R
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
##
## Copyright 2016-2017 by Claus Hunsen <[email protected]>
## Copyright 2016-2018 by Claus Hunsen <[email protected]>
## Copyright 2017 by Raphael Nömmer <[email protected]>
## Copyright 2017 by Christian Hechtl <[email protected]>
## Copyright 2017 by Felix Prasse <[email protected]>
Expand Down Expand Up @@ -302,8 +302,8 @@ y = NetworkBuilder$new(project.data = y.data, network.conf = net.conf)
# plot.print.network(g, labels = TRUE, grayscale = FALSE)

# ## set a layout and print directly
# lay = matrix(c( 20, 179, 552, 693, 956, 1091, 124, 317, 516, 615, 803, 1038,
# 245, 175, 185, 255, 253, 225, 73, 8, 75, 0, 96, 86),
# lay = matrix(c( 20, 179, 693, 552, 956, 1091, 124, 317, 516, 615, 803, 1038,
# 245, 175, 255, 185, 253, 225, 73, 8, 75, 0, 96, 86),
# nrow = 12, byrow = FALSE) # for sample graph
# g = igraph::set.graph.attribute(g, "layout", lay)
# plot.print.network(g, labels = TRUE, grayscale = FALSE)
Expand Down
20 changes: 10 additions & 10 deletions tests/test-motifs.R
Original file line number Diff line number Diff line change
Expand Up @@ -32,29 +32,29 @@ test_that("Motifs are found in sample network (remove.duplicates = TRUE).", {
igraph::V(network)[ c("D3", "D4") ],
igraph::V(network)[ c("D4", "D5") ]
)
matchings = motifs.search.in.network(network, MOTIFS.LINE, color.attr = "type", remove.duplicates = TRUE)
matchings = motifs.search.in.network(network, MOTIFS.LINE, remove.duplicates = TRUE)
expect_equal(matchings, expected, info = "Line motif")

## Triangle motif (positive)
expected = list(
igraph::V(network)[ c("D1", "D2", "A1") ]
)
matchings = motifs.search.in.network(network, MOTIFS.TRIANGLE.POSITIVE, color.attr = "type", remove.duplicates = TRUE)
matchings = motifs.search.in.network(network, MOTIFS.TRIANGLE.POSITIVE, remove.duplicates = TRUE)
expect_equal(matchings, expected, info = "Triangle motif (positive)")

## Triangle motif (negative)
expected = list(
igraph::V(network)[ c("D1", "D2", "A1") ],
igraph::V(network)[ c("D5", "D6", "A6") ]
)
matchings = motifs.search.in.network(network, MOTIFS.TRIANGLE.NEGATIVE, color.attr = "type", remove.duplicates = TRUE)
matchings = motifs.search.in.network(network, MOTIFS.TRIANGLE.NEGATIVE, remove.duplicates = TRUE)
expect_equal(matchings, expected, info = "Triangle motif (negative)")

## Square motif (positive)
expected = list(
igraph::V(network)[ c("D4", "D5", "A5", "A6") ]
)
matchings = motifs.search.in.network(network, MOTIFS.SQUARE.POSITIVE, color.attr = "type", remove.duplicates = TRUE)
matchings = motifs.search.in.network(network, MOTIFS.SQUARE.POSITIVE, remove.duplicates = TRUE)
expect_equal(matchings, expected, info = "Square motif (positive)")

## Square motif (negative)
Expand All @@ -64,7 +64,7 @@ test_that("Motifs are found in sample network (remove.duplicates = TRUE).", {
igraph::V(network)[ c("D4", "D5", "A5", "A6") ],
igraph::V(network)[ c("D4", "D6", "A5", "A6") ]
)
matchings = motifs.search.in.network(network, MOTIFS.SQUARE.NEGATIVE, color.attr = "type", remove.duplicates = TRUE)
matchings = motifs.search.in.network(network, MOTIFS.SQUARE.NEGATIVE, remove.duplicates = TRUE)
expect_equal(matchings, expected, info = "Square motif (negative)")

})
Expand All @@ -86,15 +86,15 @@ test_that("Motifs are found in sample network (remove.duplicates = FALSE).", {
igraph::V(network)[ c("D3", "D4") ], # unordered: D4, D3
igraph::V(network)[ c("D4", "D5") ] # unordered: D5, D4
)
matchings = motifs.search.in.network(network, MOTIFS.LINE, color.attr = "type", remove.duplicates = FALSE)
matchings = motifs.search.in.network(network, MOTIFS.LINE, remove.duplicates = FALSE)
expect_equal(matchings, expected, info = "Line motif")

## Triangle motif (positive)
expected = list(
igraph::V(network)[ c("D1", "D2", "A1") ],
igraph::V(network)[ c("D1", "D2", "A1") ] # unordered: D2, D1, A1
)
matchings = motifs.search.in.network(network, MOTIFS.TRIANGLE.POSITIVE, color.attr = "type", remove.duplicates = FALSE)
matchings = motifs.search.in.network(network, MOTIFS.TRIANGLE.POSITIVE, remove.duplicates = FALSE)
expect_equal(matchings, expected, info = "Triangle motif (positive)")

## Triangle motif (negative)
Expand All @@ -104,15 +104,15 @@ test_that("Motifs are found in sample network (remove.duplicates = FALSE).", {
igraph::V(network)[ c("D5", "D6", "A6") ],
igraph::V(network)[ c("D5", "D6", "A6") ] # unordered: D6, D5, A1
)
matchings = motifs.search.in.network(network, MOTIFS.TRIANGLE.NEGATIVE, color.attr = "type", remove.duplicates = FALSE)
matchings = motifs.search.in.network(network, MOTIFS.TRIANGLE.NEGATIVE, remove.duplicates = FALSE)
expect_equal(matchings, expected, info = "Triangle motif (negative)")

## Square motif (positive)
expected = list(
igraph::V(network)[ c("D4", "D5", "A5", "A6") ],
igraph::V(network)[ c("D4", "D5", "A5", "A6") ] # unordered: D5, D4, A5, A6
)
matchings = motifs.search.in.network(network, MOTIFS.SQUARE.POSITIVE, color.attr = "type", remove.duplicates = FALSE)
matchings = motifs.search.in.network(network, MOTIFS.SQUARE.POSITIVE, remove.duplicates = FALSE)
expect_equal(matchings, expected, info = "Square motif (positive)")

## Square motif (negative)
Expand All @@ -126,7 +126,7 @@ test_that("Motifs are found in sample network (remove.duplicates = FALSE).", {
igraph::V(network)[ c("D4", "D5", "A5", "A6") ], # unordered: D5, D4, A5, A6
igraph::V(network)[ c("D4", "D6", "A5", "A6") ] # unordered: D6, D4, A5, A6
)
matchings = motifs.search.in.network(network, MOTIFS.SQUARE.NEGATIVE, color.attr = "type", remove.duplicates = FALSE)
matchings = motifs.search.in.network(network, MOTIFS.SQUARE.NEGATIVE, remove.duplicates = FALSE)
expect_equal(matchings, expected, info = "Square motif (negative)")

})
Expand Down
4 changes: 2 additions & 2 deletions util-core-peripheral.R
Original file line number Diff line number Diff line change
Expand Up @@ -996,13 +996,13 @@ get.author.class = function(author.data.frame, calc.base.name, result.limit = NU
sapply(author.cumsum, function(x) isTRUE(all.equal(x, author.class.threshold)))
))

## classify developers according to threshold
## classify authors according to threshold
core.classification = rep(FALSE, nrow(author.data))
core.classification[1:author.class.threshold.idx] = TRUE

## With no activity/collaboration occurring, all authors are classified as peripheral.
if (author.class.threshold == 0) {
logging::logwarn("No collaboration/activity occured, thus, all developer's classification is set to peripheral.")
logging::logwarn("No collaboration/activity occured, thus, all authors' classification is set to peripheral.")
core.classification = rep(FALSE, length(core.classification))
# ## old code: if we found no core author (should not happen anymore)
# } else if (!any(core.classification)) {
Expand Down
68 changes: 55 additions & 13 deletions util-motifs.R
Original file line number Diff line number Diff line change
Expand Up @@ -66,38 +66,81 @@ MOTIFS.SQUARE.NEGATIVE = igraph::make_empty_graph(directed = FALSE) +
type = c(TYPE.EDGES.INTER, TYPE.EDGES.INTER, TYPE.EDGES.INTRA))


## / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
## Mapping of vertex and edge types to numerics ----------------------------

## Map vertex and edge types to numerics
MOTIF.TYPE.MAPPING = as.data.frame(rbind(
c(character = TYPE.AUTHOR, numeric = 1),
c(character = TYPE.ARTIFACT, numeric = 2),
c(character = TYPE.EDGES.INTRA, numeric = 3),
c(character = TYPE.EDGES.INTER, numeric = 4)
))


#' Get numeric vertex types from the given \code{network}.
#'
#' For this, the actual vertex types are mapped to numerics using the pre-defined
#' mapping \code{MOTIF.TYPE.MAPPING}.
#'
#' @param network the network from which to get the vertex types
#' @param index the subset of vertices to consider [default: igraph::V(network)]
#'
#' @return the vector of numeric vertex types for the (subset of) vertices in the network
#'
#' @seealso \code{MOTIF.TYPE.MAPPING}
get.vertex.types.as.numeric = function(network, index = igraph::V(network)) {

## get the vertex attribute as factor
attr.factor = factor(igraph::get.vertex.attribute(network, "type", index))

## replace factor levels with corresponding numerics
levels(attr.factor) = sapply(levels(attr.factor), function(f) {
## get the numeric from MOTIF.TYPE.MAPPING
num = subset(MOTIF.TYPE.MAPPING, character == f, numeric, drop = TRUE)
return(num)
})
## re-create vertex-attribute vector with the numerics
attr.numeric = as.numeric(levels(attr.factor))[attr.factor]

return(attr.numeric)
}


## / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
## Motif-identification functions ------------------------------------------

#' Search for the given \code{motif} in the given \code{network}.
#'
#' The vertex attribute *"type"* is used to match the vertices in the \code{motif} with
#' the ones in the given \code{network}. This means basically that a vertex with
#' a certain value for its attribute "type" in the \code{motif} is only matched with
#' vertices in \code{network} that have the same attribute values.
#'
#' @param network The network in which the given \code{motif} is searched
#' @param motif The motif to search for in the given \code{network}
#' @param color.attr The the vertex and edge attribute that is used to match the vertices
#' and the edges in the \code{motif} with the ones in the given \code{network}.
#' This means that a vertex A with the attribute declared in \code{color.attr}
#' in the \code{motif} is only matched with vertices with the same attribute in
#' the network. The same holds for edges.
#' @param remove.duplicates If \code{remove.duplicates == TRUE}, any duplicate matched motifs are
#' removed. This logical value basically resembles the idea of respecting
#' the order within a matched motif or not.
#'
#' @return A list of vertex sequences denoting the matched motifs, ordered by \code{color.attr}
#' and "name" vertex attributes
#' @return A list of vertex sequences denoting the matched motifs, ordered by "type" and "name"
#' vertex attributes
#'
#' @seealso \code{igraph::subgraph_isomorphisms} (method "vf2")
#'
#' @examples
#' motifs.search.in.network(get.sample.network(), MOTIFS.TRIANGLE.NEGATIVE, color.attr = "type", remove.duplicates = TRUE)
motifs.search.in.network = function(network, motif, color.attr = "type", remove.duplicates = TRUE) {
#' motifs.search.in.network(get.sample.network(), MOTIFS.TRIANGLE.NEGATIVE, remove.duplicates = TRUE)
motifs.search.in.network = function(network, motif, remove.duplicates = TRUE) {

## find motif in network
vs = igraph::subgraph_isomorphisms(target = network, pattern = motif, method = "vf2",
vertex.color1 = igraph::get.vertex.attribute(network, color.attr),
vertex.color2 = igraph::get.vertex.attribute(motif, color.attr))
vertex.color1 = get.vertex.types.as.numeric(network),
vertex.color2 = get.vertex.types.as.numeric(motif))

## normalize found vertex sequences (sort vertices)
vs.cleaned = lapply(vs, function(seq) {
## get types and names of vertices
types = igraph::get.vertex.attribute(network, color.attr, index = seq)
types = get.vertex.types.as.numeric(network, index = seq)
names = igraph::get.vertex.attribute(network, "name", index = seq)

## sort vertex sequence by types and names
Expand Down Expand Up @@ -160,7 +203,6 @@ motifs.count = function(network, motifs, remove.duplicates = TRUE, raw.data = FA
motifs.search.in.network(
network = network,
motif = motif,
color.attr = "type",
remove.duplicates = remove.duplicates
)
})
Expand Down
20 changes: 10 additions & 10 deletions util-networks.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@ requireNamespace("igraph") # networks
## / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
## Vertex and edge types ---------------------------------------------------

## node types
TYPE.AUTHOR = 1
TYPE.ARTIFACT = 2
## vertex types
TYPE.AUTHOR = "Author"
TYPE.ARTIFACT = "Artifact"

# edge types
TYPE.EDGES.INTRA = 3
TYPE.EDGES.INTER = 4
## edge types
TYPE.EDGES.INTRA = "Unipartite"
TYPE.EDGES.INTER = "Bipartite"


## / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /
Expand Down Expand Up @@ -790,20 +790,20 @@ construct.network.from.list = function(list, network.conf, directed = FALSE) {
## get vertex data
nodes = unique(set[, 1])

## break if there is no developer
## break if there is no author
if (length(nodes) < 1) {
return(NULL)
}

## if there is only one developer, just create the node, but no edges
## if there is only one author, just create the node, but no edges
if (length(nodes) == 1) {
edges = data.frame()
attr(edges, "nodes.processed") = nodes # store set of processed nodes
return(edges)
}

## get combinations
combinations = combn(nodes, 2) # all unique pairs of developers
combinations = combn(nodes, 2) # all unique pairs of authors

## construct edge list
edges = apply(combinations, 2, function(comb) {
Expand Down Expand Up @@ -911,7 +911,7 @@ add.edges.for.bipartite.relation = function(net, net1.to.net2, network.conf) {
vertex.sequence.for.edges = parallel::mcmapply(function(d, a.df) {
a = a.df[["data.vertices"]]
new.edges = lapply(a, function(vert) {
igraph::V(net)[d, vert] # get two vertices from source network: c(developer, artifact)
igraph::V(net)[d, vert] # get two vertices from source network: c(author, artifact)
})
return(new.edges)
}, names(net1.to.net2), net1.to.net2)
Expand Down
Loading

0 comments on commit f07ee11

Please sign in to comment.