Skip to content

Commit

Permalink
to v0.8.1
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastien-plutniak committed Jul 13, 2022
1 parent 6d8a155 commit ab3e853
Show file tree
Hide file tree
Showing 36 changed files with 573 additions and 436 deletions.
7 changes: 4 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
Package: archeofrag
Type: Package
Title: Refitting and Spatial Analysis in Archaeology
Version: 0.8
Date: 2022-03-08
Version: 0.8.1
Date: 2022-07-13
Authors@R: person("Sebastien", "Plutniak", email = "sebastien.plutniak@posteo.net", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-6674-3806"))
Author: Sebastien Plutniak [aut, cre] (<https://orcid.org/0000-0002-6674-3806>)
Maintainer: Sebastien Plutniak <sebastien.plutniak@posteo.net>
Description: Methods to analyse fragmented objects in archaeology using refitting relationships between fragments scattered in archaeological spatial units (e.g. stratigraphic layers). Graphs and graph theory are used to model archaeological observations. The package is mainly based on the 'igraph' package for graph analysis. Functions can: 1) create, manipulate, and simulate fragmentation graphs, 2) measure the cohesion and admixture of archaeological spatial units, and 3) characterise the topology of a specific set of refitting relationships. An empirical dataset is also provided as an example.
License: GPL-3
Repository: CRAN
Encoding: UTF-8
Depends: igraph, RBGL
Imports:
igraph,
graphics,
stats,
grDevices,
methods,
utils
Suggests:
RBGL,
knitr,
rmarkdown,
markdown
Expand Down
51 changes: 46 additions & 5 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,52 @@ export(make_sr_graph)
export(make_crsr_graph)
export(make_frag_object)
exportClasses(Frag.object)
import(igraph)
importFrom(grDevices, rainbow, rgb)
importFrom(grDevices, rgb)
importFrom(graphics, plot, hist)
importFrom(methods, new)
importFrom(utils, combn)
importFrom(stats, na.omit, sd)
importFrom(stats, wilcox.test)
importFrom(RBGL, boyerMyrvoldPlanarityTest)
importFrom(stats, na.omit, sd, wilcox.test)
importFrom(igraph,
add_edges,
add_layout_,
add_vertices,
as_edgelist,
as_graphnel,
bibcoupling,
components,
component_wise,
complementer,
"%--%",
decompose,
degree,
delete_vertex_attr,
delete_vertices,
diameter,
distance_table,
E,
edge_attr,
ego,
gorder,
graph_attr,
graph_from_adjacency_matrix,
graph_from_data_frame,
gsize,
induced_subgraph,
is_igraph,
is_directed,
layout_with_fr,
make_ring,
make_graph,
plot.igraph,
set_graph_attr,
set_vertex_attr,
simplify,
subgraph.edges,
subgraph_isomorphisms,
transitivity,
union,
V,
vertex_attr,
vertex_attr_names,
with_fr)

7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@

# archeofrag 0.8.1
Released: 2022-07-13

* all functions from other packages are tagged with their package.
* the RBGL is moved to the 'suggested' packages list, the functionalities related to planarity are now optional.
* igraph functions' names are updated.
* creation of a utils.R file, including internal functions to check the fragmentation graph and their "layer" argument.

# archeofrag 0.8
Released: 2022-03-08
Expand Down
12 changes: 7 additions & 5 deletions R/frag.cycles.R
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@


.detect.cycle <- function(graph, x){
pattern <- make_ring(x) # create the pattern to detect:
cycles.list <- subgraph_isomorphisms(pattern, graph)
pattern <- igraph::make_ring(x) # create the pattern to detect:
cycles.list <- igraph::subgraph_isomorphisms(pattern, graph)
res <- data.frame()
if(length(cycles.list) != 0){
res <- do.call(rbind, cycles.list) # convert the list to a data frame
Expand All @@ -19,10 +19,12 @@
.max.cycles.only(x-1, res) # recursive call
}

#' @export
#
frag.cycles <- function(graph, kmax, max.cycles.only=FALSE) {
if (! is.igraph(graph)) stop("Not an igraph object")
if(graph_attr(graph, "frag_type") == "connection and similarity" ){
# tests:
.check.frag.graph(graph)

if(igraph::graph_attr(graph, "frag_type") == "connection and similarity" ){
warning("Cycle detection in a 'connection and similarity' fragmentation graph is meaningless.")
}
if( ! is.numeric(kmax)){
Expand Down
22 changes: 12 additions & 10 deletions R/frag.diameters.R
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@

#' @export
frag.diameters <- function(graph, cumulative=FALSE)
{
if( ! is.igraph(graph)) stop("Not a graph object")
if( ! is.null(graph_attr(graph, "frag_type")) ) {
if(graph_attr(graph, "frag_type") == "connection and similarity"){
warning("Diameter distribution is meaningless for 'connection and similarity' fragmentation graphs")
#
frag.diameters <- function(graph, cumulative=FALSE){
# tests:
.check.frag.graph(graph)

if( ! is.null(igraph::graph_attr(graph, "frag_type")) ) {
if(igraph::graph_attr(graph, "frag_type") == "connection and similarity"){
warning("Diameter distribution is meaningless for 'connection and similarity' fragmentation graphs.")
}
}
if(! is.logical(cumulative)) stop("The 'cumulative' parameter must be logical.")

g.list <- decompose(graph)
diameter.v <- sapply(g.list, diameter, weights=NA, directed=FALSE, unconnected=FALSE)
diameter.v <- hist(diameter.v, breaks=0:max(diameter.v), plot=FALSE)$count
# main body:
g.list <- igraph::decompose(graph)
diameter.v <- sapply(g.list, igraph::diameter, weights=NA, directed=FALSE, unconnected=FALSE)
diameter.v <- graphics::hist(diameter.v, breaks=0:max(diameter.v), plot=FALSE)$count
if(cumulative){
diameter.v <- rev(cumsum(rev(diameter.v))) / sum(diameter.v)
}
Expand Down
97 changes: 44 additions & 53 deletions R/frag.edges.weighting.R
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
.euclidean.distance <- function(graph, x, y, z){
coords <- cbind(name = V(graph)$name,
x = get.vertex.attribute(graph, x),
y = get.vertex.attribute(graph, y),
z = get.vertex.attribute(graph, z))
e.list <- get.edgelist(graph)
coords <- cbind(name = igraph::V(graph)$name,
x = igraph::vertex_attr(graph, x),
y = igraph::vertex_attr(graph, y),
z = igraph::vertex_attr(graph, z))
e.list <- igraph::as_edgelist(graph)
colnames(e.list) <- c("name1", "name2")
e.list <- merge(e.list, coords, by.x="name1", by.y="name", sort=FALSE)
e.list <- merge(e.list, coords, by.x="name2", by.y="name",
Expand All @@ -27,12 +27,12 @@
.get.morpho.spatial.params <- function(graph, x, y, z){
# input: a graph and the names for x y z attributes
# output: a data frame with the distance and morpho parameters for the graph edges
e.list <- get.edgelist(graph)
e.list <- igraph::as_edgelist(graph)
e.list <- data.frame(e.list)
e.list$id <- 1:nrow(e.list) # a an it to sort the row later
colnames(e.list) <- c("name1", "name2", "id")
morpho.df <- cbind(name = V(graph)$name,
morphometry = V(graph)$morphometry)
morpho.df <- cbind(name = igraph::V(graph)$name,
morphometry = igraph::V(graph)$morphometry)
e.list <- merge(e.list, morpho.df, by.x="name1", by.y="name", sort=FALSE)
e.list <- merge(e.list, morpho.df, by.x="name2", by.y="name",
suffixes=c("1", "2"), sort=FALSE)
Expand All @@ -49,7 +49,7 @@

# compute spatial distances (this is done in this function to avoid repeating 3 times the command)
e.list$distance <- 1 # default value
coords <- c(x, y, z)[ c(x, y, z) %in% vertex_attr_names(graph) ]
coords <- c(x, y, z)[ c(x, y, z) %in% igraph::vertex_attr_names(graph) ]
if( length(coords) > 1) { # if at least two coordinates
e.list$distance <- .euclidean.distance(graph, x, y, z) + 1 # +1 to ensure a neutral value when all distances=0
}
Expand All @@ -67,12 +67,12 @@

.set.edge.weight <- function(g){
#edges weight = sum of the degrees * transitivity-based index
if(gsize(g) == 0 ) return(0)
e.list <- as_edgelist(g)
if(igraph::gsize(g) == 0 ) return(0)
e.list <- igraph::as_edgelist(g)
colnames(e.list) <- c("src", "tgt")
v.list <- cbind(name = V(g)$name,
deg = igraph::degree(g),
trans = transitivity(g, type = "localundirected",
trans = igraph::transitivity(g, type = "localundirected",
isolates = "zero", weights = NULL))
e.list <- merge(e.list, v.list, by.x="src", by.y="name", sort=FALSE)
e.list <- merge(e.list, v.list, by.x="tgt", by.y="name", sort=FALSE)
Expand All @@ -86,57 +86,48 @@
e.list$SumDegree * e.list$trans.factor * size.factor
}

frag.edges.weighting <- function(graph, layer.attr, morphometry="", x="", y="", z="")
{
if(! is.igraph(graph)){
stop("Not a graph object")
}
if(! is.character(layer.attr)) {
stop("A character value is expected for the 'layer.attr' parameter.")
}
if (is.null(layer.attr)){
stop("No 'layer.attr' argument")
}
if( ! layer.attr %in% names(vertex_attr(graph)) ){
stop(paste("No '", layer.attr, "' vertices attribute", sep=""))
}
frag.edges.weighting <- function(graph, layer.attr, morphometry="", x="", y="", z=""){
# tests:
.check.frag.graph(graph)
.check.layer.argument(graph, layer.attr)

if(! is.character(morphometry)) {
stop("A character value is expected for the 'morphometry' parameter.")
}
if(sum(! sapply(c(x,y,z), is.character)) != 0) {
stop("Character values are expected for the 'x', 'y' and 'z' parameters.")
}

if (is.null(V(graph)$name)){
V(graph)$name <- seq(1:gorder(graph))
if(is.null(V(graph)$name)){
igraph::V(graph)$name <- seq(1:gorder(graph))
}

missing.coords <- c(x, y, z)[ ! c(x, y, z) %in% c("", vertex_attr_names(graph)) ]
missing.coords <- c(x, y, z)[ ! c(x, y, z) %in% c("", igraph::vertex_attr_names(graph)) ]
if(length(missing.coords) > 0){
warning(paste("Missing coordinates:", paste(missing.coords, collapse = ", ") ))
}

V(graph)$morphometry <- 1 # set default value
igraph::V(graph)$morphometry <- 1 # set default value
if( morphometry != ""){
if( morphometry %in% names(vertex_attr(graph)) ){
V(graph)$morphometry <- vertex_attr(graph, morphometry)
if( morphometry %in% names(igraph::vertex_attr(graph)) ){
igraph::V(graph)$morphometry <- igraph::vertex_attr(graph, morphometry)
}else{
stop(paste("No '", morphometry, "' vertices attribute", sep=""))
}
}
if(! is.numeric(V(graph)$morphometry)){
if(! is.numeric(igraph::V(graph)$morphometry)){
stop("Numeric values are required for the 'morphometry' parameter.")
}

layers <- vertex_attr(graph, layer.attr)
layers <- igraph::vertex_attr(graph, layer.attr)
layers.u <- unique(layers)
if(length(layers.u) > 2){
stop("There are more than two layers.")
}

v1 <- layers == layers.u[1]
v2 <- layers == layers.u[2]
E(graph)$id <- 1:gsize(graph)
igraph::E(graph)$id <- 1:igraph::gsize(graph)

# get the max morphometric/spatial values observed in the data set:
params <- .get.morpho.spatial.params(graph, x, y, z)
Expand All @@ -147,23 +138,23 @@ frag.edges.weighting <- function(graph, layer.attr, morphometry="", x="", y="",

# add a "distance" edge attribute if necessary:
if(! is.null(params$distance)){
E(graph)$distance <- params$distance
igraph::E(graph)$distance <- params$distance
}

# generate subgraphs
g1 <- subgraph.edges(graph, E(graph)[ V(graph)[v1] %--% V(graph)[v1] ])
g2 <- subgraph.edges(graph, E(graph)[ V(graph)[v2] %--% V(graph)[v2] ])
g12 <- subgraph.edges(graph, E(graph)[ V(graph)[v1] %--% V(graph)[v2] ])
g1 <- igraph::subgraph.edges(graph, igraph::E(graph)[ igraph::V(graph)[v1] %--% igraph::V(graph)[v1] ])
g2 <- igraph::subgraph.edges(graph, igraph::E(graph)[ igraph::V(graph)[v2] %--% igraph::V(graph)[v2] ])
g12 <- igraph::subgraph.edges(graph, igraph::E(graph)[ igraph::V(graph)[v1] %--% igraph::V(graph)[v2] ])

# extract edges indices:
e1 <- E(graph)$id %in% E(g1)$id
e2 <- E(graph)$id %in% E(g2)$id
e12 <- E(graph)$id %in% E(g12)$id
e1 <- igraph::E(graph)$id %in% igraph::E(g1)$id
e2 <- igraph::E(graph)$id %in% igraph::E(g2)$id
e12 <- igraph::E(graph)$id %in% igraph::E(g12)$id

# get the morphometric/spatial parameters of the edges compute the
# morphometric/spatial factor for the edges of each subgraphs:
morpho.spatial.factor.g1 <- 0
if(gsize(g1) > 0){
if(igraph::gsize(g1) > 0){
params1 <- .get.morpho.spatial.params(g1, x, y, z)
morpho.spatial.factor.g1 <- apply(params1, 1, function(x){
.morpho.spatial.factor(morpho1 = x[1],
Expand All @@ -177,7 +168,7 @@ frag.edges.weighting <- function(graph, layer.attr, morphometry="", x="", y="",
}

morpho.spatial.factor.g2 <- 0
if(gsize(g2) > 0){
if(igraph::gsize(g2) > 0){
params2 <- .get.morpho.spatial.params(g2, x, y, z)
morpho.spatial.factor.g2 <- apply(params2, 1, function(x){
.morpho.spatial.factor(morpho1 = x[1],
Expand All @@ -191,7 +182,7 @@ frag.edges.weighting <- function(graph, layer.attr, morphometry="", x="", y="",
}

morpho.spatial.factor.g12 <- 0
if(gsize(g12) > 0){
if(igraph::gsize(g12) > 0){
params12 <- .get.morpho.spatial.params(g12, x, y, z)
morpho.spatial.factor.g12 <- apply(params12, 1, function(x){
.morpho.spatial.factor(morpho1 = x[1],
Expand All @@ -205,19 +196,19 @@ frag.edges.weighting <- function(graph, layer.attr, morphometry="", x="", y="",
}

# compute the weights for the edges of the 3 subsets:
E(graph)[ e1 ]$weight <- .set.edge.weight(g1)
E(graph)[ e2 ]$weight <- .set.edge.weight(g2)
E(graph)[ e12]$weight <- .set.edge.weight(g12)
igraph::E(graph)[ e1 ]$weight <- .set.edge.weight(g1)
igraph::E(graph)[ e2 ]$weight <- .set.edge.weight(g2)
igraph::E(graph)[ e12]$weight <- .set.edge.weight(g12)
# apply the morpho/spatial modifier is required:
if(sum(sapply(list(morphometry, x, y, z), function(x) x != ""))){
E(graph)[ e1 ]$weight <- E(graph)[e1]$weight * morpho.spatial.factor.g1
E(graph)[ e2 ]$weight <- E(graph)[e2]$weight * morpho.spatial.factor.g2
E(graph)[ e12]$weight <- E(graph)[e12]$weight* morpho.spatial.factor.g12
igraph::E(graph)[ e1 ]$weight <- igraph::E(graph)[e1]$weight * morpho.spatial.factor.g1
igraph::E(graph)[ e2 ]$weight <- igraph::E(graph)[e2]$weight * morpho.spatial.factor.g2
igraph::E(graph)[ e12]$weight <- igraph::E(graph)[e12]$weight* morpho.spatial.factor.g12
}

# add tags to the edges:
E(graph)$scope <- "intra"
E(graph)[e12]$scope <- "extra"
igraph::E(graph)$scope <- "intra"
igraph::E(graph)[e12]$scope <- "extra"

graph
}
14 changes: 6 additions & 8 deletions R/frag.get.layers.R
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@

frag.get.layers <- function(graph, layer.attr, sel.layers){
if(! is.igraph(graph)) stop("Not a graph object")
if( ! is.character(layer.attr)) stop("The parameter 'layer.attr' requires a character value.")
if(is.null(vertex_attr(graph, layer.attr))) stop("The parameter 'layer.attr' is required.")
if( ! layer.attr %in% names(vertex_attr(graph)) ){
stop(paste("No '", layer.attr, "' vertices attribute", sep=""))
}
# tests:
.check.frag.graph(graph)
.check.layer.argument(graph, layer.attr)

layers <- vertex_attr(graph, layer.attr)
# function:
layers <- igraph::vertex_attr(graph, layer.attr)
if(sum(sel.layers %in% layers) != length(sel.layers)) stop("Some of the 'selected layers' are not in the 'layers' vector.")

g.list <- lapply(sel.layers,
function(x) induced_subgraph(graph, V(graph)[layers == x] ))
function(x) igraph::induced_subgraph(graph, V(graph)[layers == x] ))
names(g.list) <- sel.layers
g.list
}
Loading

0 comments on commit ab3e853

Please sign in to comment.