Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LightGraphs interface fixes, add more tests #4

Merged
merged 8 commits into from
Sep 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions src/graph_interface.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import LightGraphs:
inneighbors, outneighbors, is_directed, add_edge!

import SimpleWeightedGraphs:
add_edge!, get_weight
add_edge!, get_weight, add_vertex!, vertices

import Base:
eltype, zero
import Base: zero

### LightGraphs interface
nv(g::AbstractSpatialGraph) = nv(g.graph)
Expand All @@ -22,8 +21,31 @@ has_vertex(g::AbstractSpatialGraph, v) = has_vertex(g.graph, v)
inneighbors(g::AbstractSpatialGraph, v) = inneighbors(g.graph, v)
outneighbors(g::AbstractSpatialGraph, v) = outneighbors(g.graph, v)
is_directed(g::AbstractSpatialGraph) = is_directed(g.graph)
zero(g::AbstractSpatialGraph) = zero(g.graph)
function Base.zero(g::AbstractRasterGraph)
if g.graph isa SimpleGraph
SimpleRasterGraph(
zero(typeof(g.graph)),
g.vertex_raster
)
elseif g.graph isa SimpleDiGraph
SimpleRasterDiGraph(
zero(typeof(g.graph)),
g.vertex_raster
)
elseif g.graph isa SimpleWeightedGraph
WeightedRasterGraph(
SimpleWeightedGraph{eltype(g.graph), weighttype(g.graph)}(),
g.vertex_raster
)
elseif g.graph isa SimpleWeightedDiGraph
WeightedRasterDiGraph(
SimpleWeightedDiGraph{eltype(g.graph), weighttype(g.graph)}(),
g.vertex_raster
)
end
end
add_edge!(g::AbstractSpatialGraph, a::Integer, b::Integer, c::Number) = add_edge!(g.graph, a, b, c)
add_vertex!(g::AbstractSpatialGraph) = add_vertex!(g.graph)

### SimpleWeightedGraphs
get_weight(g::WeightedRasterGraph, a::Integer, b::Integer) = get_weight(g.graph, a, b)
Expand Down
11 changes: 10 additions & 1 deletion src/rastergraphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,16 @@ function make_raster_graph(

sources = Vector{Int64}()
destinations = Vector{Int64}()
weighted && (node_weights = Vector{Float64}())

weighted && (weight_type = eltype(raster))

if weighted && (weight_type <: Integer)
@info ("weight_raster eltype is $(weight_type). " *
"Promoting to Float64.")
weight_type = Float64
end

weighted && (node_weights = Vector{weight_type}())

# Add the edges
# Only need to do neighbors down or to the right for undirected graphs
Expand Down
34 changes: 34 additions & 0 deletions test/lg_interface.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using SpatialGraphs, Test, GeoData, LightGraphs, SimpleWeightedGraphs
## This script tests methods for the LightGraph interface that aren't already
## used in other tests

A_array = Array{Float32}(undef, (3, 4, 1))
A_array[:,:,:] = [1, 3, 2, 0.5, 10, 8, 5, -9999, 3, 1, 2, 6]
x = X(1:4)
y = Y(1:3)
band = Band(1:1)

weight_raster = GeoArray(A_array, (y, x, band), missingval = -9999)
rasgraph = weightedrastergraph(weight_raster)

@test nv(rasgraph) == maximum(rasgraph.vertex_raster)
num_edge = ne(rasgraph)
@test vertices(rasgraph) == 1:maximum(rasgraph.vertex_raster)
@test eltype(rasgraph) == Int # Should always be Int64 (or int32 on 32-bit)
@test edgetype(rasgraph) == SimpleWeightedEdge{eltype(rasgraph), eltype(A_array)}

for i in 1:maximum(rasgraph.vertex_raster)
@test has_vertex(rasgraph, i)
end

# In undirected graph incoming neighbors should equal outgoing
@test inneighbors(rasgraph, 1) == outneighbors(rasgraph, 1)

empty = zero(rasgraph)

add_vertices!(empty, maximum(rasgraph.vertex_raster))
add_edge!(empty, 1, 4, Float32(0.5))

@test nv(empty) == maximum(rasgraph.vertex_raster)
@test has_edge(empty, 1, 4)
@test get_weight(empty, 1, 4) == Float32(0.5)
25 changes: 23 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
using Test, SpatialGraphs
using GeoData, LightGraphs, SimpleWeightedGraphs, SpatialGraphs, Test

@testset "Simple Raster Graph Construction" begin
include("simplerastergraphs.jl")
end

@testset "Weighted Raster Graph Construction" begin
include("weightedrastergraphs.jl")
Expand All @@ -10,4 +14,21 @@ end

@testset "Weighted Raster DiGraph Construction" begin
include("weightedrasterdigraphs.jl")
end
end

@testset "LightGraphs Interface" begin
include("lg_interface.jl")
end

printstyled("Checking that Base.show works...\n", bold = true)

A_array = Array{Float64}(undef, (3, 4, 1))
A_array[:,:,:] = [1, 3, 2, 0.5, 10, 8, 5, -9999, 3, 1, 2, 6]
x = X(1:4)
y = Y(1:3)
band = Band(1:1)

weight_raster = GeoArray(A_array, (y, x, band), missingval = -9999)
rasgraph = weightedrastergraph(weight_raster)
show(rasgraph);print("\n")

5 changes: 4 additions & 1 deletion test/simplerasterdigraphs.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using GeoData, LightGraphs, SimpleWeightedGraphs, SpatialGraphs, Test

condition_array = Array{Float64}(undef, (3, 4, 1))
condition_array[:,:,:] = [1, 3, 5, 2, 4, 8, 5, -9999, 2, 3, 6, 7]
condition_array[:,:,:] = [1, 0.5, 5, 2, 4, 8, 5, -9999, 2, 3, 6, 7]

x = X(1:4)
y = Y(1:3)
Expand Down Expand Up @@ -52,3 +52,6 @@ for i in 1:length(graph_edges)
col_diff = abs(source_coords[2] - dest_coords[2])
@test col_diff <= 1
end

@test is_directed(rasgraph)
@test zero(rasgraph).vertex_raster == rasgraph.vertex_raster
57 changes: 57 additions & 0 deletions test/simplerastergraphs.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using GeoData, LightGraphs, SimpleWeightedGraphs, SpatialGraphs, Test

array = Array{Int}(undef, (3, 4, 1))
array[:,:,:] = [1, 1, 1, 1, 2, 2, 2, -9999, 2, 3, 3, 3]

x = X(1:4)
y = Y(1:3)
band = Band(1:1)

raster = GeoArray(array, (y, x, band), missingval = -9999)

compare = ==
rasgraph = simplerastergraph(
raster,
directed = false,
condition = compare
)

# no vertices in NoData pixels?
@test (rasgraph.vertex_raster .== 0) ==
((raster .== raster.missingval) .|
isnan.(raster))

# Is the number of of vertices correct, and is the range of values correct?
@test sort(collect(rasgraph.vertex_raster[rasgraph.vertex_raster .!= 0])) ==
collect(1:sum(
(raster .!= raster.missingval) .&
(!).(isnan.(raster))
))

graph_edges = collect(edges(rasgraph))

# Test that the edges are correct and have proper weights
for i in 1:length(graph_edges)
source_i = src(graph_edges[i])
dest_i = dst(graph_edges[i])

source_coords = findall(rasgraph.vertex_raster .== source_i)[1]
dest_coords = findall(rasgraph.vertex_raster .== dest_i)[1]

# Check that condition is met
@test compare(
raster[source_coords],
raster[dest_coords]
)

# Test that source row is within 1 step of dest row
row_diff = abs(source_coords[1] - dest_coords[1])
@test row_diff <= 1

# Test that source column is within 1 step of dest row
col_diff = abs(source_coords[2] - dest_coords[2])
@test col_diff <= 1
end

@test is_directed(rasgraph) == false
@test zero(rasgraph).vertex_raster == rasgraph.vertex_raster
5 changes: 4 additions & 1 deletion test/weightedrasterdigraphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ A_array = Array{Float64}(undef, (3, 4, 1))
A_array[:,:,:] = [1, 3, 2, 0.5, 10, 8, 5, -9999, 3, 1, 2, 6]

condition_array = Array{Float64}(undef, (3, 4, 1))
condition_array[:,:,:] = [1, 3, 5, 2, 4, 8, 5, -9999, 2, 3, 6, 7]
condition_array[:,:,:] = [1, 0.5, 5, 2, 4, 8, 5, -9999, 2, 3, 6, 7]

x = X(1:4)
y = Y(1:3)
Expand Down Expand Up @@ -68,3 +68,6 @@ for i in 1:length(graph_edges)
weight_raster[dest_coords])
end
end

@test is_directed(rasgraph)
@test zero(rasgraph).vertex_raster == rasgraph.vertex_raster
44 changes: 40 additions & 4 deletions test/weightedrastergraphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ band = Band(1:1)

weight_raster = GeoArray(A_array, (y, x, band), missingval = -9999)
weight_raster2d = GeoArray(A_array[:, :, 1], (y, x), missingval = -9999)
rasgraph2d = weightedrastergraph(weight_raster2d)
rasgraph = weightedrastergraph(weight_raster)
rasgraph2d = weightedrastergraph(
weight_raster2d,
connect_using_avg_weights = false
)
rasgraph = weightedrastergraph(weight_raster, connect_using_avg_weights = false)

# Test that graphs are the same regardless of whether weight_raster has Band dim
@test rasgraph2d.graph == rasgraph.graph
Expand Down Expand Up @@ -48,11 +51,44 @@ for i in 1:length(graph_edges)
# Test that the weight is what it should be (assumes connect_using_avg_weights = true in graph construction)
if (row_diff == 1 && col_diff == 1) # get diagonal average
@test weight_i ==
SpatialGraphs.res_diagonal_avg(weight_raster[source_coords],
SpatialGraphs.cond_diagonal_avg(weight_raster[source_coords],
weight_raster[dest_coords])
else
@test weight_i ==
SpatialGraphs.res_cardinal_avg(weight_raster[source_coords],
SpatialGraphs.cond_cardinal_avg(weight_raster[source_coords],
weight_raster[dest_coords])
end
end

# check that no edges exist that shouldn't
vertex_raster = rasgraph.vertex_raster
for src_row in 1:size(vertex_raster)[1]
for src_col in 1:size(vertex_raster)[2]
for dst_row in 1:size(vertex_raster)[1]
for dst_col in 1:size(vertex_raster)[2]
if ((vertex_raster[src_row, src_col] == 0) |
(vertex_raster[dst_row, dst_col] == 0))
continue
elseif ((abs(src_row - dst_row) <= 1) &
(abs(src_col - dst_col) <= 1)) & (
(abs(src_row - dst_row) > 0) |
(abs(src_col - dst_col) > 0))
@test has_edge(
rasgraph,
vertex_raster[src_row, src_col],
vertex_raster[dst_row, dst_col]
) == true
else
@test (has_edge(
rasgraph,
vertex_raster[src_row, src_col],
vertex_raster[dst_row, dst_col]
) == false)
end
end
end
end
end

@test is_directed(rasgraph) == false
@test zero(rasgraph).vertex_raster == rasgraph.vertex_raster