Commit 5d9cbce2 authored by Facundo Muñoz's avatar Facundo Muñoz ®️
Browse files

read_network(): read network data

parent c97f9ffe
......@@ -21,6 +21,7 @@ Imports:
classInt,
geojsonio,
geojsonlint,
igraph,
methods,
maps,
maptools,
......@@ -43,7 +44,7 @@ Suggests:
rmarkdown,
roxygen2,
testthat
RoxygenNote: 6.0.1
RoxygenNote: 6.1.1
URL: https://github.com/Cirad-ASTRE/mapMCDA
BugReports: https://github.com/Cirad-ASTRE/mapMCDA/issues
VignetteBuilder: knitr
......@@ -11,6 +11,7 @@ export(load_dir)
export(load_layer)
export(mapMCDA_app)
export(mapMCDA_datasets)
export(read_network)
export(resolution)
export(risk_layer)
export(risk_plot)
......@@ -22,3 +23,4 @@ import(methods)
import(raster)
import(rgdal)
import(sp)
importFrom(igraph,graph_from_data_frame)
#' Read and interpret network data
#'
#' Read a csv file with a specific format (see Details) and intepret
#' it as network directed data with possibly weighted edges.
#'
#' The file must be plain text with comma-separated columns and varaible
#' names in the first line.
#' There must be either 6 or 7 columns in the same order and of the
#' same types as follows:
#' \itemize{
#' \item origin character
#' \item destination character
#' \item lon_orig numeric (decimal degrees, WGS84)
#' \item lat_orig numeric (decimal degrees, WGS84)
#' \item lon_dest numeric (decimal degrees, WGS84)
#' \item lat_dest numeric (decimal degrees, WGS84)
#' \item volume Optional. directed flux in some consistent unit
#' }
#'
#' Variable names can be different. If strings contain spaces they must
#' be quoted.
#'
#' @param x character. Path of csv file
#'
#' @return object of class \code{igraph}
#' @importFrom igraph graph_from_data_frame
#' @export
#'
#' @examples
#' d <- data.frame(from = "A", to = "B", fx = 0, fy = 0, tx = 1, ty = 1)
#' tf <- tempfile()
#' write.csv(d, tf, row.names = FALSE)
#' read_network(tf)
read_network <- function(x) {
## Read file
dat <- read.csv(x, stringsAsFactors = FALSE)
## Message on input format
input_format <- c(
"Input data format:",
"Comma-separated plain text file with variable names in the first row.",
"Decimal point symbol: dot.",
"Variable names can be different, but the order and types
must be respected:",
"",
"origin character",
"destination character",
"lon_orig numeric (decimal degrees, WGS84)",
"lat_orig numeric (decimal degrees, WGS84)",
"lon_dest numeric (decimal degrees, WGS84)",
"lat_dest numeric (decimal degrees, WGS84)",
"volume Optional. directed flux in some consistent unit."
)
## Check number of columns
if (ncol(dat) < 6 | ncol(dat) > 7) {
stop("Expected 6 or 7 columns, observed ", ncol(dat),
message(paste(input_format, collapse = "\n")))
}
## Check type of columns
## transform any column of class 'integer' to 'numeric'
class(dat[vapply(dat, is.integer, T)]) <- "numeric"
col_classes <- sapply(dat, class)
exp_classes <- c(rep("character", 2), rep("numeric", length(col_classes)-2))
if( any(idx <- col_classes != exp_classes) ) {
nms.idx <- paste(names(dat)[idx], collapse = ", ")
stop(
"Unexpected type in column(s) ", nms.idx,
message(paste(input_format, collapse = "\n"))
)
}
## Check duplicated edges
if ( any(idx <- duplicated(dat[, 1:2])) ) {
print(dat[which(idx), 1:2])
stop("The links above appear more than once")
}
## Check graph is directed
## At least one edge contains a reciprocal
if( !any(duplicated(rbind(dat[, 1:2], dat[, 2:1]))) ) {
stop(
"All the links are unidirectional.\n",
"If you are sure that the network is directed, add at least one
reciprocal link with a weight of 0 and proceed."
)
}
## Links
e_list <- dat[, -(3:6)]
## Coordinates of vertices
v_coord <- unique(
rbind(
setNames(dat[, c(1, 3:4)], c("Node", "Lon", "Lat")),
setNames(dat[, c(2, 5:6)], c("Node", "Lon", "Lat"))
)
)
v_coord <- v_coord[order(v_coord$Node),]
v_coord$Node <- as.factor(v_coord$Node)
## Check consistency of coordinates
if (any((idx <- tapply(v_coord$Node, v_coord$Node, length)) > 1)) {
idx.nodes <- names(idx)[idx > 1]
stop("Node(s) ", idx.nodes, " have inconsistent coordinates in the dataset.")
}
ans <- igraph::graph_from_data_frame(e_list, vertices = v_coord, directed = TRUE)
return(ans)
}
from,to,x,y,x,y,volume
B,A,11.671892969661,5.07524565350228,10.4752357653861,5.11625239679984,16.7
C,A,13.0929847436669,4.73604695288819,10.4752357653861,5.11625239679984,17.5
D,A,13.2560676538308,2.28246654951196,10.4752357653861,5.11625239679984,0
E,A,13.127502479115,3.09597725926486,10.4752357653861,5.11625239679984,76
A,B,10.4752357653861,5.11625239679984,11.671892969661,5.07524565350228,13
C,B,13.0929847436669,4.73604695288819,11.671892969661,5.07524565350228,16
D,B,13.2560676538308,2.28246654951196,11.671892969661,5.07524565350228,28.8
E,B,13.127502479115,3.09597725926486,11.671892969661,5.07524565350228,115.4
A,C,10.4752357653861,5.11625239679984,13.0929847436669,4.73604695288819,13.4
B,C,11.671892969661,5.07524565350228,13.0929847436669,4.73604695288819,72.1
D,C,13.2560676538308,2.28246654951196,13.0929847436669,4.73604695288819,24.6
E,C,13.127502479115,3.09597725926486,13.0929847436669,4.73604695288819,0
A,D,10.4752357653861,5.11625239679984,13.2560676538308,2.28246654951196,5.2
B,D,11.671892969661,5.07524565350228,13.2560676538308,2.28246654951196,25.9
C,D,13.0929847436669,4.73604695288819,13.2560676538308,2.28246654951196,14.2
E,D,13.127502479115,3.09597725926486,13.2560676538308,2.28246654951196,0
A,E,10.4752357653861,5.11625239679984,13.127502479115,3.09597725926486,30.5
B,E,11.671892969661,5.07524565350228,13.127502479115,3.09597725926486,0
C,E,13.0929847436669,4.73604695288819,13.127502479115,3.09597725926486,12.1
D,E,13.2560676538308,2.28246654951196,13.127502479115,3.09597725926486,7.3
......@@ -4,7 +4,8 @@
\alias{distance_map}
\title{Compute a distance map to spatial features}
\usage{
distance_map(x, boundaries, res = resolution(boundaries, min_ncells = 100))
distance_map(x, boundaries, res = resolution(boundaries, min_ncells =
100))
}
\arguments{
\item{x}{Spatial* object with relevant spatial features.}
......
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/network.R
\name{read_network}
\alias{read_network}
\title{Read and interpret network data}
\usage{
read_network(x)
}
\arguments{
\item{x}{character. Path of csv file}
}
\value{
object of class \code{igraph}
}
\description{
Read a csv file with a specific format (see Details) and intepret
it as network directed data with possibly weighted edges.
}
\details{
The file must be plain text with comma-separated columns and varaible
names in the first line.
There must be either 6 or 7 columns in the same order and of the
same types as follows:
\itemize{
\item origin character
\item destination character
\item lon_orig numeric (decimal degrees, WGS84)
\item lat_orig numeric (decimal degrees, WGS84)
\item lon_dest numeric (decimal degrees, WGS84)
\item lat_dest numeric (decimal degrees, WGS84)
\item volume Optional. directed flux in some consistent unit
}
Variable names can be different. If strings contain spaces they must
be quoted.
}
\examples{
d <- data.frame(from = "A", to = "B", fx = 0, fy = 0, tx = 1, ty = 1)
tf <- tempfile()
write.csv(d, tf, row.names = FALSE)
read_network(tf)
}
## Fake animal mobility data
## For testing network data
if (!file.exists(system.file("testdata", "mobility.csv", package = "mapMCDA"))) {
set.seed(20190115)
n_markets <- 5
markets <- spsample(rgeos::gUnaryUnion(admin), n_markets, type = "random")
mobility <-
subset(
expand.grid(
from = LETTERS[seq.int(n_markets)],
to = LETTERS[seq.int(n_markets)],
KEEP.OUT.ATTRS = FALSE
),
from != to # remove diagonals
)
mobility <- cbind(
mobility,
coordinates(markets)[factor(mobility$from), ]
)
mobility <- cbind(
mobility,
coordinates(markets)[factor(mobility$to), ]
)
mobility$volume <- round(rt(n_markets*(n_markets-1), df = 1, ncp = 10), 1)
## Set a few of the least important edges to zero
n_zeros <- floor(nrow(mobility)/5)
mobility$volume[sample(nrow(mobility), n_zeros, prob = 1/mobility$volume)] <- 0
rownames(mobility) <- NULL
if (!file.exists(tdp <- file.path(system.file(package = "mapMCDA"), "testdata"))) {
dir.create(tdp)
}
write.csv(mobility, file.path(tdp, "mobility.csv"), row.names = FALSE, quote = FALSE)
}
context("Network data")
admin <- mapMCDA_datasets()$cmr_admin3
## Input data format (assumed)
## variable names can be different, but the order and types
## must be respected:
##
## origin character
## destination character
## lon_orig numeric (decimal degrees, WGS84)
## lat_orig numeric (decimal degrees, WGS84)
## lon_dest numeric (decimal degrees, WGS84)
## lat_dest numeric (decimal degrees, WGS84)
## volume Optional. directed flux in some consistent unit.
test_that("Interpret network data", {
nf <- system.file("testdata", "mobility.csv", package = "mapMCDA")
expect_error(x <- read_network(nf), NA)
expect_s3_class(x, "igraph")
})
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment