From 2039eb2721693b89a5ec22d1569b03bc077e3e8d Mon Sep 17 00:00:00 2001 From: Michael Krabbe Borregaard Date: Sat, 8 Sep 2018 12:12:00 +0200 Subject: [PATCH] Adapt the type hierarchy --- src/ComMatrix.jl | 6 +++-- src/Constructor_helperfunctions.jl | 4 ++-- src/Constructors.jl | 23 +++++++++---------- src/DataTypes.jl | 36 +++++++++++++----------------- src/Gridfunctions.jl | 16 +++++++------ src/Subsetting.jl | 25 ++++++++++++--------- test/Assemblage_tests.jl | 2 +- 7 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/ComMatrix.jl b/src/ComMatrix.jl index db7cbd1..8c2462b 100644 --- a/src/ComMatrix.jl +++ b/src/ComMatrix.jl @@ -19,8 +19,8 @@ end occupancy(com::AbstractComMatrix) = occupancy(occurrences(com)) richness(com::AbstractComMatrix) = richness(occurrences(com)) -occurring(com::AbstractComMatrix) = occurring(occurrences(com)) -occupied(com::AbstractComMatrix) = occupied(occurrences(com)) +occurring(com::AbstractComMatrix, idx...) = occurring(occurrences(com), idx...) +occupied(com::AbstractComMatrix, idx...) = occupied(occurrences(com), idx...) const nspecies = nthings nthings(com::AbstractComMatrix) = size(com.occurrences, 1) @@ -29,6 +29,8 @@ const nsites = nplaces nplaces(com::AbstractComMatrix) = size(com.occurrences, 2) nplaces(sd::SiteData) = size(coordinates(sd.site), 1) nplaces(sd::SELocations) = DataFrames.ncol(sd.sitestats) +nplaces(gr::GridData) = size(gr.indices, 1) +nplaces(pd::PointData) = size(pd.coords, 1) nrecords(com::AbstractComMatrix) = _nnz(occurrences(com)) diff --git a/src/Constructor_helperfunctions.jl b/src/Constructor_helperfunctions.jl index a0459aa..fe13aa8 100644 --- a/src/Constructor_helperfunctions.jl +++ b/src/Constructor_helperfunctions.jl @@ -96,7 +96,7 @@ function dropspecies!(occ::SpeciesData) occ.traits = occ.traits[occur,:] end -function dropbyindex!(site::PointData, indicestokeep) +function dropbyindex!(site::Locations{PointData}, indicestokeep) site.coords = site.coords[indicestokeep,:] site.sitestats = site.sitestats[indicestokeep,:] end @@ -106,7 +106,7 @@ maxrange(x) = diff([extrema(x)...])[1] # remember here - something wrong with the indices, make sure they are based from 1! -function dropbyindex!(site::GridData, indicestokeep) +function dropbyindex!(site::Locations{GridData}, indicestokeep) site.indices = site.indices[indicestokeep,:] site.sitestats = site.sitestats[indicestokeep,:] site.grid.xmin = xrange(site.grid)[minimum(site.indices[:,1])] diff --git a/src/Constructors.jl b/src/Constructors.jl index 8372b56..b7334d9 100644 --- a/src/Constructors.jl +++ b/src/Constructors.jl @@ -40,11 +40,11 @@ function Assemblage(occ::ComMatrix, coords::AbstractMatrix; occ, coords, sitestat = match_commat_coords(occ, coords, sitestat) end - Assemblage(createSELocations(coords, cdtype, sitestat), SpeciesData(occ, traits)) + Assemblage(createLocations(coords, cdtype, sitestat), SpeciesData(occ, traits)) end -function Assemblage(site::S, occ::SpeciesData{D}; - dropemptyspecies::Bool = false, dropemptysites::Bool = false) where {D <: Real, S <: SELocations} +function Assemblage(site::P, occ::SpeciesData{D}; + dropemptyspecies::Bool = false, dropemptysites::Bool = false) where {D <: Real, P <: SELocations} if dropemptyspecies dropspecies!(occ) @@ -52,19 +52,19 @@ function Assemblage(site::S, occ::SpeciesData{D}; if dropemptysites dropsites!(occ, site) end - Assemblage{S}{T}(site, occ) + Assemblage{D, P}(site, occ) end -function createSELocations(coords::AbstractMatrix, cdtype::coordstype = auto, #by design, this is not type stable, but maybe that is OK for type constructors +function createLocations(coords::AbstractMatrix, cdtype::coordstype = auto, #by design, this is not type stable, but maybe that is OK for type constructors sitestat = DataFrames.DataFrame(sites = sitenames(occ))) - cdtype == pointdata && return PointData(coords, sitestat) - cdtype == griddata && return GridData(coords, sitestat) + cdtype == pointdata && return Locations{PointData}(PointData(coords), sitestat) + cdtype == griddata && return Locations{GridData}(GridData(coords), sitestat) if cdtype == auto try - return GridData(coords, sitestat) + return Locations{GridData}(GridData(coords), sitestat) catch - return PointData(coords, sitestat) + return Locations{PointData}(PointData(coords), sitestat) end end end @@ -131,9 +131,8 @@ function ComMatrix(occurrences; specnames = :auto, sitenames = :auto, sitecolumn ComMatrix{eltype(occurrences)}(sparse(occurrences), string.(specnames), string.(sitenames)) end -function GridData(coords::AbstractMatrix{<:Union{AbstractFloat, Missings.Missing}}, - sitestats::DataFrames.DataFrame = DataFrames.DataFrame(id = 1:size(coords,1))) +function GridData(coords::AbstractMatrix{<:Union{AbstractFloat, Missing}}) grid = creategrid(coords) indices = getindices(coords, grid) - GridData(indices, grid, sitestats) + GridData(indices, grid) end diff --git a/src/DataTypes.jl b/src/DataTypes.jl index 434cd26..6bdf284 100644 --- a/src/DataTypes.jl +++ b/src/DataTypes.jl @@ -6,9 +6,9 @@ # implement with unions abstract type SESpatialData <: EcoBase.AbstractPlaces end abstract type SELocations <: EcoBase.AbstractLocations end -abstract type SEPointData <: SELocations end -abstract type SEGrid <: EcoBase.AbstractGrid end abstract type SEThings{D <: Real} <: EcoBase.AbstractThings end +abstract type SEGrid <: EcoBase.AbstractGrid end +abstract type SEPointData end abstract type AbstractComMatrix{ D<:Real } end @@ -16,7 +16,7 @@ abstract type AbstractComMatrix{ D<:Real } end # I could implement sitestats as a Dict with several DataFrames to make space for big data sets, but I prefer to not do this now. Example below. # I could do a lot more with immutable types if I had a clearer view/copy implementation -mutable struct GridTopology +mutable struct GridTopology <: EcoBase.AbstractGrid xmin::Number xcellsize::Number xcells::Int @@ -32,28 +32,22 @@ mutable struct Bbox ymax::Number end - # Do I need sitenames here? I think so, they should match those in sitestats, and be separate mutable struct PointData <: SEPointData coords::Matrix{Float64} - sitestats::DataFrames.DataFrame - # inner constructor - function PointData(coords, sitestats = DataFrames.DataFrame(id = 1:size(coords,1))) - - DataFrames.nrow(sitestats) == size(coords, 1) || throw(DimensionMismatch("Wrong number of rows in sitestat")) # a little check for the right number - new(coords, sitestats) - end end - mutable struct GridData <: SEGrid indices::Matrix{Int} grid::GridTopology - sitestats::DataFrames.DataFrame +end - function GridData(indices, grid, sitestats = DataFrames.DataFrame(id = 1:size(coords,1))) - DataFrames.nrow(sitestats) == size(indices, 1) || throw(DimensionMismatch("Wrong number of rows in sitestat")) # a little check for the right number - new(indices, grid, sitestats) +mutable struct Locations{T<:Union{GridData, PointData}} <: SELocations + coords::T + sitestats::DataFrames.DataFrame + function Locations{T}(coords, sitestats = DataFrames.DataFrame(id = 1:size(coords,1))) where T + DataFrames.nrow(sitestats) == nsites(coords) || throw(DimensionMismatch("Wrong number of rows in sitestat")) # a little check for the right number + new(coords, sitestats) end end @@ -77,18 +71,18 @@ end SpeciesData(commatrix::ComMatrix{D}, traits) where D<:Real = SpeciesData{D}(commatrix, traits) # Not really sure what this type is for -mutable struct SiteData{S} <: SESpatialData where S <: SELocations +mutable struct SiteData{S} <: SESpatialData where S <: Locations site::S end -abstract type SEAssemblage{D<:Real, P<:SELocations} <: EcoBase.AbstractAssemblage{D, SpeciesData, P} end +abstract type SEAssemblage{D<:Real, T<:SEThings, P<:SELocations} <: EcoBase.AbstractAssemblage{D, T, P} end -mutable struct Assemblage{D<:Real, P<:SELocations} <: SEAssemblage{D, P} # A type to keep subtypes together, ensuring that they are all aligned at all times +mutable struct Assemblage{D<:Real, P<:Locations} <: SEAssemblage{D, SpeciesData{D}, P} # A type to keep subtypes together, ensuring that they are all aligned at all times site::P - occ::SpeciesData + occ::SpeciesData{D} # inner constructor - function Assemblage{D, P}(site::P, occ::SpeciesData, com::ComMatrix{D}) where {P <: SELocations, D <: Real} + function Assemblage{D, P}(site::P, occ::SpeciesData{D}) where {P <: SELocations, D <: Real} size(occurrences(occ), 2) == size(coordinates(site), 1) || error("Length mismatch between occurrence matrix and coordinates") #TODO activate this # sitenames(occ) == sitenames(site) || error("sitenames do not match") #I need a constructor that matches them up actively new(site, occ) diff --git a/src/Gridfunctions.jl b/src/Gridfunctions.jl index 4a631d1..81487c2 100644 --- a/src/Gridfunctions.jl +++ b/src/Gridfunctions.jl @@ -6,12 +6,14 @@ xcells(g::GridTopology) = g.xcells ycells(g::GridTopology) = g.ycells boundingbox(g::GridTopology) = Bbox(xmin(g), xmax(g), ymin(g), ymax(g)) -@forward_func SEGrid.grid xmin, ymin, xcellsize, ycellsize, cellsize, xcells, ycells, cells, xrange, yrange, xmax, ymax, boundingbox +@forward_func GridData.grid xmin, ymin, xcellsize, ycellsize, cellsize, xcells, ycells, cells, xrange, yrange, xmax, ymax, boundingbox +@forward_func Locations{GridData}.coords xmin, ymin, xcellsize, ycellsize, cellsize, xcells, ycells, cells, xrange, yrange, xmax, ymax, boundingbox + show(io::IO, b::Bbox) = println(io, "xmin:\t$(b.xmin)\nxmax:\t$(b.xmax)\nymin:\t$(b.ymin)\nymax:\t$(b.ymax)") -show(io::IO, g::SEGrid) = println(io, - """Spatial grid - Lower left corner: $(xmin(g)), $(ymin(g)) - Cellsizes : $(xcellsize(g)), $(ycellsize(g)) - Size : $(xcells(g)), $(ycells(g)) - """) +show(io::IO, g::GridData) = println(io, + """ + Spatial grid + lower left : $(xmin(g)), $(ymin(g)) + cellsizes : $(xcellsize(g)), $(ycellsize(g)) + size : $(xcells(g)), $(ycells(g))""") diff --git a/src/Subsetting.jl b/src/Subsetting.jl index f52b3b1..4db8a02 100644 --- a/src/Subsetting.jl +++ b/src/Subsetting.jl @@ -14,24 +14,27 @@ mutable struct SubSpeciesData{D <: Real} <: SEThings{D} traits::DataFrames.SubDataFrame end -mutable struct SubGridData <: SEGrid +mutable struct SubGridData <: EcoBase.AbstractGrid indices::SubArray{Int,2} grid::GridTopology - sitestats::DataFrames.SubDataFrame end -mutable struct SubPointData <: SEPointData +mutable struct SubPointData coords::SubArray{Float64,2} +end + +mutable struct SubLocations{T<:Union{SubGridData, SubPointData}} <: SELocations + coords::T sitestats::DataFrames.SubDataFrame end -mutable struct SubAssemblage{D <: Real, P <: Union{SubGridData, SubPointData}} <: SEAssemblage{D, P} # A type to keep subtypes together, ensuring that they are all aligned at all times +mutable struct SubAssemblage{D <: Real, P <: SubLocations} <: SEAssemblage{D, SubSpeciesData{D}, P} # A type to keep subtypes together, ensuring that they are all aligned at all times site::P - occ::SubSpeciesData + occ::SubSpeciesData{D} end # TODO delete -mutable struct SubSiteData{S} <: SESpatialData where S <: Union{SubGridData, SubPointData} +mutable struct SubSiteData{S} <: SESpatialData where S <: SubLocations site::S end @@ -50,12 +53,12 @@ function view(com::AbstractComMatrix; species = 1:nspecies(com), sites = 1:nsite SubComMatrix(view(com.occurrences, spec, sit), view(com.specnames, spec), view(com.sitenames, sit)) #TODO change the order of these in the object to fit the array index order end -view(pd::SEPointData, sites) = SubPointData(view(pd.coords, sites), view(pd.sitestats, sites)) - -view(gd::SEGrid, sites) = SubGridData(view(gd.indices, sites, :), gd.grid, view(gd.sitestats, sites)) +view(pd::SEPointData, sites) = SubPointData(view(pd.coords, sites)) +view(gd::SEGrid, sites) = SubGridData(view(gd.indices, sites, :), gd.grid) +view(gd::SELocations, sites) = SubLocations{SubGridData}(view(gd.coords, sites), view(gd.sitestats, sites)) view(sp::SESpatialData, sites = 1:nsites(sp)) = SubSiteData(view(sp.site, sites)) -function view(asm::SEAssemblage; species = 1:nspecies(asm), sites = 1:nsites(asm), dropsites = false, dropspecies = false, dropempty = false) + function view(asm::SEAssemblage{D, P}; species = 1:nspecies(asm), sites = 1:nsites(asm), dropsites = false, dropspecies = false, dropempty = false) where D where P occ = view(asm.occ, species = species, sites = sites) site = view(asm.site, sites) @@ -69,7 +72,7 @@ function view(asm::SEAssemblage; species = 1:nspecies(asm), sites = 1:nsites(asm occ = view(occ, species = occurring(occ)) end - SubAssemblage(site, occ) + SubAssemblage{D, typeof(site)}(site, occ) end Assemblage(assm::SubAssemblage) = copy(assm) diff --git a/test/Assemblage_tests.jl b/test/Assemblage_tests.jl index 5ddba18..9d80538 100644 --- a/test/Assemblage_tests.jl +++ b/test/Assemblage_tests.jl @@ -7,7 +7,7 @@ using Test amphdat = CSV.read(joinpath(dirname(pathof(SpatialEcology)), "..", "data", "amph_Europe.csv")) amph = Assemblage(amphdat[4:end], amphdat[1:3], sitecolumns = false) - @test typeof(amph) == Assemblage{SpatialEcology.GridData,Bool} + @test typeof(amph) == Assemblage{Bool,SpatialEcology.Locations{SpatialEcology.GridData}} # accesseors @test extrema(richness(amph)) == (1, 20)