From 589d48bd8df7096dc71454908061084411a9f363 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e?= Date: Mon, 30 Mar 2020 11:50:36 -0400 Subject: [PATCH 01/11] :arrow_right: add workflow actions --- .github/workflows/CI.yml | 52 ++++++++++++++++++++++++++++++ .github/workflows/CompatHelper.yml | 24 ++++++++++++++ Project.toml | 4 +-- 3 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/CI.yml create mode 100644 .github/workflows/CompatHelper.yml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 000000000..e00875c8d --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,52 @@ +name: CI +on: + - push + - pull_request +jobs: + test: + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + version: + - '1.3' + - '1.4' + - 'nightly' + os: + - ubuntu-latest + - macOS-latest + - windows-latest + arch: + - x64 + steps: + - uses: actions/checkout@v2 + - uses: julia-actions/setup-julia@v1 + with: + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + - uses: julia-actions/julia-buildpkg@latest + - uses: julia-actions/julia-runtest@latest + - uses: julia-actions/julia-processcoverage@v1 + - uses: codecov/codecov-action@v1 + with: + file: ./lcov.info + flags: unittests + name: codecov-umbrella + fail_ci_if_error: false + token: ${{ secrets.CODECOV }} + docs: + name: Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: julia-actions/setup-julia@v1 + with: + version: '1.4' + - run: | + julia --project=docs -e ' + using Pkg + Pkg.develop(PackageSpec(path=pwd())) + Pkg.instantiate()' + - run: julia --project=docs docs/make.jl + env: + GITHUB_TOKEN: ${{ secrets.TOKEN }} diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml new file mode 100644 index 000000000..bccaf37f3 --- /dev/null +++ b/.github/workflows/CompatHelper.yml @@ -0,0 +1,24 @@ +name: CompatHelper + +on: + schedule: + - cron: '00 * * * *' + +jobs: + CompatHelper: + runs-on: ${{ matrix.os }} + strategy: + matrix: + julia-version: [1.4.0] + julia-arch: [x86] + os: [ubuntu-latest] + steps: + - uses: julia-actions/setup-julia@latest + with: + version: ${{ matrix.julia-version }} + - name: Pkg.add("CompatHelper") + run: julia -e 'using Pkg; Pkg.add("CompatHelper")' + - name: CompatHelper.main() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: julia -e 'using CompatHelper; CompatHelper.main()' diff --git a/Project.toml b/Project.toml index 08b4b5cb9..db366db7a 100644 --- a/Project.toml +++ b/Project.toml @@ -2,7 +2,7 @@ name = "EcologicalNetworks" uuid = "f03a62fe-f8ab-5b77-a061-bb599b765229" authors = ["Timothée Poisot "] repo = "https://github.com/PoisotLab/EcologicalNetworks.jl" -version = "0.2.2" +version = "0.3.0" [deps] Combinatorics = "861a8166-3701-5b0c-9a16-15d98fcdc6aa" @@ -16,7 +16,7 @@ Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" [compat] -julia = "1" +julia = "1.3" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" From f9ecc9a081c24c3be024452c6bb27fb00cc140eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e?= Date: Mon, 30 Mar 2020 11:50:55 -0400 Subject: [PATCH 02/11] :fire: remove travis file --- .travis.yml | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0ef146773..000000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: julia - -os: - - linux - -julia: - - 1.0 - -before_script: - - julia -e 'using Pkg; Pkg.add("Test")' - -after_success: - - julia -e 'using Pkg; cd(Pkg.dir("EcologicalNetworks")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder()); Codecov.submit(Codecov.process_folder())' - - julia -e 'using Pkg; Pkg.add("Documenter")' - - julia -e 'using Pkg; cd(Pkg.dir("EcologicalNetworks")); include(joinpath("docs", "make.jl"))' From 1b60aca879bbd5002d56ac1285adf0207eee14ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e?= Date: Mon, 30 Mar 2020 11:57:44 -0400 Subject: [PATCH 03/11] :truck: doc update --- docs/Project.toml | 5 + docs/make.jl | 19 +-- docs/src/assets/documenter.css | 232 --------------------------------- docs/src/var/plots.md | 158 ---------------------- 4 files changed, 11 insertions(+), 403 deletions(-) create mode 100644 docs/Project.toml delete mode 100644 docs/src/assets/documenter.css delete mode 100644 docs/src/var/plots.md diff --git a/docs/Project.toml b/docs/Project.toml new file mode 100644 index 000000000..1b9ab1f81 --- /dev/null +++ b/docs/Project.toml @@ -0,0 +1,5 @@ +[deps] +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" + +[compat] +Documenter = "0.24" diff --git a/docs/make.jl b/docs/make.jl index 87ca0000a..7d8c5b0a6 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,12 +1,7 @@ -using Pkg - -tmp_packages = ["EcologicalNetworksPlots", "Plots", "Documenter"] - -push!(LOAD_PATH,"../src/") - +import Pkg Pkg.activate(".") -Pkg.add.(tmp_packages) # IMPORTANT +push!(LOAD_PATH,"../src/") using Documenter using EcologicalNetworks @@ -22,8 +17,7 @@ makedocs( "Interface" => [ "Types" => "interface/types.md", "Conversions" => "interface/conversions.md", - "Core functions" => "interface/highlevel.md", - "Plotting" => "var/plots.md" + "Core functions" => "interface/highlevel.md" ], "Network measures" => [ "Links" => "properties/links.md", @@ -39,14 +33,13 @@ makedocs( "Random networks" => [ "Null models" => "random/null.md", "Structural models" => "random/structure.md" - ] + ] ] ) deploydocs( deps = Deps.pip("pygments", "python-markdown-math"), repo = "github.com/PoisotLab/EcologicalNetworks.jl.git", - devbranch = "master" + devbranch = "master", + push_preview = true ) - -Pkg.rm.(tmp_packages) # IMPORTANT diff --git a/docs/src/assets/documenter.css b/docs/src/assets/documenter.css deleted file mode 100644 index 8faa09129..000000000 --- a/docs/src/assets/documenter.css +++ /dev/null @@ -1,232 +0,0 @@ -@import url('https://fonts.googleapis.com/css?family=Fira+Mono:400,500,700|Fira+Sans+Condensed:400,400i,500,500i|Fira+Sans:400,400i,500,500i&subset=greek,greek-ext'); - -:root { - --toc-width: 15em; - --max-width: 45em; - --int-padding: 1em; - - --color-bg: #fcfcfc; - --color-fg: #303030; - --color-accent: #1C9696; - - --font-mono: "Fira Mono"; - --font-body: "Fira Sans"; - --font-meta: "Fira Sans Condensed"; - - --package-name: "EcologicalNetworks" -} - -body { - color: var(--color-fg); - background-color: var(--color-bg); - font-family: var(--font-body); - line-height: 1.5; - font-size: 16px; -} - -b, strong { - font-weight: 500; -} - -h1, h2, h3, h4, h5, h6, .nav-anchor { - font-weight: 500; - font-family: var(--font-meta); - color: #777; -} - -a, a:hover, a:visited { - text-decoration: none; - color: var(--color-accent); -} - -nav.toc, article { - padding: var(--int-padding); -} - -nav.toc { - font-family: var(--font-meta); - width: var(--toc-width); - position: fixed; - height: 100vh; - top: 0; - left: 0; - transition-property: left; - transition-duration: 0.3s; - transition-timing-function: ease-out; - z-index: 2; - display: flex; - flex-flow: column nowrap; - overflow-y: auto; - padding: 1em 0 0 0; - text-align: center; - background-color: var(--color-bg); -} - -nav.toc.show { - left: 0; - box-shadow: 0px 0px 4px 0px #888; - font-size: 95%; -} - -nav .logo { - max-width: var(--toc-width); - max-height: 7em; - text-align: center; -} - -nav.toc h1 { - color: var(--color-fg); - font-weight: 500; - font-size: 1.35em; -} - -nav.toc ul { - padding-left: 15px; -} - -nav.toc li { - line-height: 28px; -} - -nav.toc li.current { - font-weight: 500; -} - -nav.toc li.current ul.internal { - font-weight: 400; -} - -nav.toc li.current ul.internal a { - color: #777 !important; -} - - -nav.toc ul, nav.toc li { - text-align: left; - list-style: none; -} - -article { - max-width: var(--max-width); -} - -section.docstring { - margin-bottom: 4em; -} - -section.docstring:last-of-type { - margin-bottom: 0; -} - -.docstring-header { - font-size: 110%; - font-weight: 500; - color: #777; -} - -.docstring-binding { - color: black; - -} - -pre, code, kbd { - font-family: var(--font-mono); -} - -header { - font-family: var(--font-meta); -} - -header a, header a:hover, header a:visited{ - font-weight: 500; -} - -header ul, header li { - list-style: none; - padding-left: 0; - display: inline; -} - -header li { - display: inline-block; -} - -header li::before { - content: "›"; - color: #777; - padding-left: 5px; - padding-right: 5px; -} - -header li:first-of-type::before { - content: var(--package-name); - color: black; - font-weight: 500; - padding-right: 1em; - padding-left: 0px; -} - -header hr { - display: none; -} - -.edit-page { - display: none; -} - -@media screen and (max-width: 768px) { - header nav { - display: none; - } - nav.toc { - left: -15em; - } - article { - margin-left: 0em !important; - } - header #topbar { - position: fixed; - left: 0; - top: 0; - width: 100vw; - background-color: var(--color-bg); - z-index: 10; - box-shadow: 0px 0px 2px 0px #777; - padding: var(--int-padding); - font-size: 1.2em; - } - header #topbar a { - padding-left: 2em; - } - article { - margin-top: 4em; - } - .logo { - display: none; - } -} - -@media screen and (min-width: 768px) { - header #topbar { - display: none; - } - header nav { - margin-bottom: 3em; - } -} - -@media screen and (max-width: 75em) { - article { - margin-left: var(--toc-width); - } -} - -@media screen and (min-width: 75em) { - article { - margin: 0px auto; - } -} - -.footer { - display: none; -} diff --git a/docs/src/var/plots.md b/docs/src/var/plots.md deleted file mode 100644 index b8a4853f4..000000000 --- a/docs/src/var/plots.md +++ /dev/null @@ -1,158 +0,0 @@ -Plotting functions are part of the `EcologicalNetworksPlot`, which requires -`Plot` to work. `EcologicalNetworksPlot` can be installed from the central -*Julia* package repository. - -## Initial layouts - -```@docs -initial -``` - -```@docs -RandomInitialLayout -BipartiteInitialLayout -FoodwebInitialLayout -CircularInitialLayout -``` - -## Layouts - -### Force-directed layout - -```@docs -ForceDirectedLayout -``` - -### Circular layout - -```@docs -CircularLayout -``` - -### Static layouts - -```@docs -NestedBipartiteLayout -``` - -## Apply layout to network - -```@docs -position! -``` - -## Examples - -```@setup default -using EcologicalNetworks -using EcologicalNetworksPlots -using Plots -``` - -## Static layouts - -### Nested - -```@example default -Unes = web_of_life("M_SD_033") -I = initial(BipartiteInitialLayout, Unes) -position!(NestedBipartiteLayout(0.4), I, Unes) -plot(I, Unes, aspectratio=1) -scatter!(I, Unes, bipartite=true) -``` - -### Circular - -```@example default -Unes = web_of_life("M_SD_033") -I = initial(CircularInitialLayout, Unes) -position!(CircularLayout(), I, Unes) -plot(I, Unes, aspectratio=1) -scatter!(I, Unes, bipartite=true) -``` - -## Dynamic layouts - -### Force directed - -```@example default -Umod = web_of_life("M_PA_003") -I = initial(RandomInitialLayout, Umod) -for step in 1:4000 - position!(ForceDirectedLayout(2.5), I, Umod) -end -plot(I, Umod, aspectratio=1) -scatter!(I, Umod, bipartite=true) -``` - -### Food web layout - -```@example default -Fweb = simplify(nz_stream_foodweb()[5]) -I = initial(FoodwebInitialLayout, Fweb) -for step in 1:4000 - position!(ForceDirectedLayout(true, false, 2.5), I, Fweb) -end -plot(I, Fweb) -scatter!(I, Fweb) -``` - -Note that we can replace some properties of the nodes in the layout *after* the -positioning algorithm occurred -- so we can, for example, use the actual -(instead of fractional) trophic level: - -```@example default -Fweb = simplify(nz_stream_foodweb()[5]) -I = initial(FoodwebInitialLayout, Fweb) -for step in 1:4000 - position!(ForceDirectedLayout(true, false, 2.5), I, Fweb) -end -tl = trophic_level(Fweb) -for s in species(Fweb) - I[s].y = tl[s] -end -plot(I, Fweb) -scatter!(I, Fweb) -``` - -## Node properties - -### Color - -```@example default -Unes = web_of_life("M_SD_033") -I = initial(BipartiteInitialLayout, Unes) -position!(NestedBipartiteLayout(0.4), I, Unes) -plot(I, Unes, aspectratio=1) -scatter!(I, Unes, bipartite=true, nodefill=degree(Unes)) -``` - -### Size - -## Advanced examples - -One important feature of the package is that the layout can contain *more* nodes -than the network. For example, we can use this to our advantage, to represent -species with a degree larger than 3 in red: - -```@example default -Umod = web_of_life("M_PA_003") -I = initial(RandomInitialLayout, Umod) -for step in 1:4000 - position!(ForceDirectedLayout(2.5), I, Umod) -end -plot(I, Umod, aspectratio=1) -scatter!(I, Umod) -N = convert(AbstractUnipartiteNetwork, convert(BinaryNetwork, Umod)) -core3 = collect(keys(filter(p -> p.second ≥ 3, degree(N)))) -plot!(I, N[core3], lc=:red) -scatter!(I, N[core3], mc=:red) -``` - -### Heatmaps - - -```@example default -Umod = web_of_life("M_PA_003") -heatmap(Umod) -``` From 7e27dff66b1496ef9c9c8dc47f7b4324ba5af1f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e?= Date: Mon, 30 Mar 2020 12:01:32 -0400 Subject: [PATCH 04/11] :heavy_plus_sign: packages for the documentation --- docs/Project.toml | 1 + docs/make.jl | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Project.toml b/docs/Project.toml index 1b9ab1f81..2eb7258e6 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,5 +1,6 @@ [deps] Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" [compat] Documenter = "0.24" diff --git a/docs/make.jl b/docs/make.jl index 7d8c5b0a6..3463f207b 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -5,7 +5,6 @@ push!(LOAD_PATH,"../src/") using Documenter using EcologicalNetworks -using EcologicalNetworksPlots using Random makedocs( From b969c8a6a6139d12465b348b63b30288f5426dd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e?= Date: Mon, 30 Mar 2020 12:03:51 -0400 Subject: [PATCH 05/11] :memo: update readme --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e70a738b8..6e233b0db 100644 --- a/README.md +++ b/README.md @@ -39,12 +39,14 @@ That's it. Now head over to the ### On `master` -[![Build Status](https://travis-ci.org/PoisotLab/EcologicalNetworks.jl.svg?branch=master)](https://travis-ci.org/PoisotLab/EcologicalNetworks.jl) -[![Coverage Status](https://coveralls.io/repos/PoisotLab/EcologicalNetworks.jl/badge.svg?branch=master&service=github)](https://coveralls.io/github/PoisotLab/EcologicalNetworks.jl?branch=master) +![CI](https://github.com/PoisotLab/EcologicalNetworks.jl/workflows/CI/badge.svg?branch=master) +![CI](https://github.com/PoisotLab/EcologicalNetworks.jl/workflows/TagBot/badge.svg?branch=master) +![CI](https://github.com/PoisotLab/EcologicalNetworks.jl/workflows/CompatHelper/badge.svg?branch=master) [![codecov.io](http://codecov.io/github/PoisotLab/EcologicalNetworks.jl/coverage.svg?branch=master)](http://codecov.io/github/PoisotLab/EcologicalNetworks.jl?branch=master) ### On `develop` -[![Build Status](https://travis-ci.org/PoisotLab/EcologicalNetworks.jl.svg?branch=develop)](https://travis-ci.org/PoisotLab/EcologicalNetworks.jl) -[![Coverage Status](https://coveralls.io/repos/github/PoisotLab/EcologicalNetworks.jl/badge.svg?branch=develop)](https://coveralls.io/github/PoisotLab/EcologicalNetworks.jl?branch=develop) +![CI](https://github.com/PoisotLab/EcologicalNetworks.jl/workflows/CI/badge.svg?branch=develop) +![CI](https://github.com/PoisotLab/EcologicalNetworks.jl/workflows/TagBot/badge.svg?branch=develop) +![CI](https://github.com/PoisotLab/EcologicalNetworks.jl/workflows/CompatHelper/badge.svg?branch=develop) [![codecov.io](http://codecov.io/github/PoisotLab/EcologicalNetworks.jl/coverage.svg?branch=develop)](http://codecov.io/github/PoisotLab/EcologicalNetworks.jl?branch=develop) From 670661be5e06efd027073d2b7d27341580f197f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e?= Date: Mon, 30 Mar 2020 12:17:04 -0400 Subject: [PATCH 06/11] :bug: fix make doc file --- docs/make.jl | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index 3463f207b..6192857cd 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,6 +1,3 @@ -import Pkg -Pkg.activate(".") - push!(LOAD_PATH,"../src/") using Documenter From 359befc47d0115d0e7c7e376e47754f18d023c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e?= Date: Mon, 30 Mar 2020 12:22:46 -0400 Subject: [PATCH 07/11] :bug: extra module imported in doc --- docs/make.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/make.jl b/docs/make.jl index 6192857cd..c83399052 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -7,7 +7,7 @@ using Random makedocs( sitename = "EcologicalNetworks", authors = "Timothée Poisot", - modules = [EcologicalNetworks, EcologicalNetworksPlots], + modules = [EcologicalNetworks], pages = [ "Index" => "index.md", "Interface" => [ From 944407f4b4bd3f63215e5b6a20cfa3c9127d6e4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e?= Date: Mon, 30 Mar 2020 21:31:21 -0400 Subject: [PATCH 08/11] :memo: doc for plots --- docs/src/index.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/src/index.md b/docs/src/index.md index 4442de064..06283d307 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -52,10 +52,11 @@ speaking a tool for analysis, it is not part of this package. Second, it helps to keep software dependency small. Most of our work using this package is done on clusters of one sort of the other, and having fewer -dependencies means that installation is easier. +dependencies means that installation is easier. `EcologicalNetworksPlots` can be +installed like any other Julia package. It is also documented on [its own +website][ENP]. -`EcologicalNetworksPlots` can be installed as with any other Julia package. It -is also documented on this website. +[ENP]: https://poisotlab.github.io/EcologicalNetworksPlots.jl/stable/ ### And worse, you forgot my favorite method! From a796260510fa715889f374343613c60b0f46724c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e?= Date: Mon, 30 Mar 2020 21:31:50 -0400 Subject: [PATCH 09/11] :person_frowning: better error messages --- src/types/constructors.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/types/constructors.jl b/src/types/constructors.jl index 60e55ff37..4ec437416 100644 --- a/src/types/constructors.jl +++ b/src/types/constructors.jl @@ -5,7 +5,7 @@ function UnipartiteNetwork(A::M) where {M<:AbstractMatrix{Bool}} end function UnipartiteNetwork(A::M, S::Vector{NT}) where {M<:AbstractMatrix{Bool}, NT} - is_valid_species(NT) || throw(ArgumentError("Not allowed")) + is_valid_species($1) || throw(ArgumentError("${NT} is not a valid type of node")) check_unipartiteness(A, S) UnipartiteNetwork{Bool,NT}(A, S) end @@ -18,7 +18,7 @@ function BipartiteNetwork(A::M) where {M<:AbstractMatrix{Bool}} end function BipartiteNetwork(A::M, T::Vector{NT}, B::Vector{NT}) where {M<:AbstractMatrix{Bool}, NT} - is_valid_species(NT) || throw(ArgumentError("Not allowed")) + is_valid_species($1) || throw(ArgumentError("${NT} is not a valid type of node")) check_bipartiteness(A, T, B) BipartiteNetwork{Bool,eltype(T)}(A, T, B) end @@ -32,7 +32,7 @@ function BipartiteProbabilisticNetwork(A::Matrix{IT}) where {IT<:AbstractFloat} end function BipartiteProbabilisticNetwork(A::Matrix{IT}, T::Vector{NT}, B::Vector{NT}) where {IT<:AbstractFloat, NT} - is_valid_species(NT) || throw(ArgumentError("Not allowed")) + is_valid_species($1) || throw(ArgumentError("${NT} is not a valid type of node")) check_bipartiteness(A, T, B) check_probability_values(A) BipartiteProbabilisticNetwork{IT,NT}(A, T, B) @@ -46,7 +46,7 @@ function BipartiteQuantitativeNetwork(A::Matrix{IT}) where {IT <: Number} end function BipartiteQuantitativeNetwork(A::Matrix{IT}, T::Vector{NT}, B::Vector{NT}) where {IT<:Number,NT} - is_valid_species(NT) || throw(ArgumentError("Not allowed")) + is_valid_species($1) || throw(ArgumentError("${NT} is not a valid type of node")) check_bipartiteness(A, T, B) BipartiteQuantitativeNetwork{IT,NT}(A, T, B) end @@ -58,7 +58,7 @@ function UnipartiteQuantitativeNetwork(A::Matrix{IT}) where {IT<:Number} end function UnipartiteQuantitativeNetwork(A::Matrix{IT}, S::Vector{NT}) where {IT<:Number,NT} - is_valid_species(NT) || throw(ArgumentError("Not allowed")) + is_valid_species($1) || throw(ArgumentError("${NT} is not a valid type of node")) check_unipartiteness(A, S) UnipartiteQuantitativeNetwork{IT,NT}(A, S) end @@ -73,7 +73,7 @@ function UnipartiteProbabilisticNetwork(A::Matrix{IT}) where {IT<:AbstractFloat} end function UnipartiteProbabilisticNetwork(A::Matrix{IT}, S::Vector{NT}) where {IT<:AbstractFloat,NT} - is_valid_species(NT) || throw(ArgumentError("Not allowed")) + is_valid_species($1) || throw(ArgumentError("${NT} is not a valid type of node")) check_unipartiteness(A, S) check_probability_values(A) UnipartiteProbabilisticNetwork{IT,NT}(A, S) From 4690292e274042887c25573a79921921dec26e86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e?= Date: Mon, 30 Mar 2020 21:44:13 -0400 Subject: [PATCH 10/11] :bug: string interpolation in error message --- src/types/constructors.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/types/constructors.jl b/src/types/constructors.jl index 4ec437416..d6477e764 100644 --- a/src/types/constructors.jl +++ b/src/types/constructors.jl @@ -5,7 +5,7 @@ function UnipartiteNetwork(A::M) where {M<:AbstractMatrix{Bool}} end function UnipartiteNetwork(A::M, S::Vector{NT}) where {M<:AbstractMatrix{Bool}, NT} - is_valid_species($1) || throw(ArgumentError("${NT} is not a valid type of node")) + is_valid_species($1) || throw(ArgumentError("$(NT) is not a valid type of node")) check_unipartiteness(A, S) UnipartiteNetwork{Bool,NT}(A, S) end @@ -18,7 +18,7 @@ function BipartiteNetwork(A::M) where {M<:AbstractMatrix{Bool}} end function BipartiteNetwork(A::M, T::Vector{NT}, B::Vector{NT}) where {M<:AbstractMatrix{Bool}, NT} - is_valid_species($1) || throw(ArgumentError("${NT} is not a valid type of node")) + is_valid_species($1) || throw(ArgumentError("$(NT) is not a valid type of node")) check_bipartiteness(A, T, B) BipartiteNetwork{Bool,eltype(T)}(A, T, B) end @@ -32,7 +32,7 @@ function BipartiteProbabilisticNetwork(A::Matrix{IT}) where {IT<:AbstractFloat} end function BipartiteProbabilisticNetwork(A::Matrix{IT}, T::Vector{NT}, B::Vector{NT}) where {IT<:AbstractFloat, NT} - is_valid_species($1) || throw(ArgumentError("${NT} is not a valid type of node")) + is_valid_species($1) || throw(ArgumentError("$(NT) is not a valid type of node")) check_bipartiteness(A, T, B) check_probability_values(A) BipartiteProbabilisticNetwork{IT,NT}(A, T, B) @@ -46,7 +46,7 @@ function BipartiteQuantitativeNetwork(A::Matrix{IT}) where {IT <: Number} end function BipartiteQuantitativeNetwork(A::Matrix{IT}, T::Vector{NT}, B::Vector{NT}) where {IT<:Number,NT} - is_valid_species($1) || throw(ArgumentError("${NT} is not a valid type of node")) + is_valid_species($1) || throw(ArgumentError("$(NT) is not a valid type of node")) check_bipartiteness(A, T, B) BipartiteQuantitativeNetwork{IT,NT}(A, T, B) end @@ -58,7 +58,7 @@ function UnipartiteQuantitativeNetwork(A::Matrix{IT}) where {IT<:Number} end function UnipartiteQuantitativeNetwork(A::Matrix{IT}, S::Vector{NT}) where {IT<:Number,NT} - is_valid_species($1) || throw(ArgumentError("${NT} is not a valid type of node")) + is_valid_species($1) || throw(ArgumentError("$(NT) is not a valid type of node")) check_unipartiteness(A, S) UnipartiteQuantitativeNetwork{IT,NT}(A, S) end @@ -73,7 +73,7 @@ function UnipartiteProbabilisticNetwork(A::Matrix{IT}) where {IT<:AbstractFloat} end function UnipartiteProbabilisticNetwork(A::Matrix{IT}, S::Vector{NT}) where {IT<:AbstractFloat,NT} - is_valid_species($1) || throw(ArgumentError("${NT} is not a valid type of node")) + is_valid_species($1) || throw(ArgumentError("$(NT) is not a valid type of node")) check_unipartiteness(A, S) check_probability_values(A) UnipartiteProbabilisticNetwork{IT,NT}(A, S) From 00afce84ded933dd027ffa863395f1d4a20d5eef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e?= Date: Mon, 30 Mar 2020 22:19:45 -0400 Subject: [PATCH 11/11] :sparkles: omnivory index --- docs/src/interface/types.md | 8 +++++--- src/EcologicalNetworks.jl | 16 +++++++++++++--- src/foodwebs/omnivory.jl | 24 ++++++++++++++++++++++++ src/types/constructors.jl | 12 ++++++------ src/types/utilities.jl | 9 ++++++--- 5 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 src/foodwebs/omnivory.jl diff --git a/docs/src/interface/types.md b/docs/src/interface/types.md index 151539cee..13a14252c 100644 --- a/docs/src/interface/types.md +++ b/docs/src/interface/types.md @@ -72,7 +72,7 @@ AbstractEcologicalNetwork ``` The type of nodes that are allowed is determined by the *non-exported* -`EcologicalNetworks.is_valid_species` function. To allow an additional type of +`EcologicalNetworks.check_species_validity` function. To allow an additional type of node, you can write the following: ~~~ julia @@ -83,11 +83,13 @@ struct Foo end import EcologicalNetworks -EcologicalNetworks.is_valid_species(::Type{Foo}) = true +function EcologicalNetworks.check_species_validity(::Type{Foo}) +end ~~~ Note that **integers are never valid species identifiers**. By default, `String` -and `Symbol` are used. +and `Symbol` are used. The function `check_species_validity` should do *nothing* +for an accepted type (and it will throw an error for any other type). ### By partiteness diff --git a/src/EcologicalNetworks.jl b/src/EcologicalNetworks.jl index 9a8219fe5..9b4eee802 100644 --- a/src/EcologicalNetworks.jl +++ b/src/EcologicalNetworks.jl @@ -38,9 +38,16 @@ include(joinpath(".", "misc/data.jl")) export web_of_life, nz_stream_foodweb, pajek function __init__() - @require Mangal="b8b640a6-63d9-51e6-b784-5033db27bef2" is_valid_species(::Mangal.MangalNode) = true - @require Mangal="b8b640a6-63d9-51e6-b784-5033db27bef2" is_valid_species(::Mangal.MangalReferenceTaxon) = true - @require GBIF="ee291a33-5a6c-5552-a3c8-0f29a1181037" is_valid_species(::GBIF.GBIFTaxon) = true + @require Mangal="b8b640a6-63d9-51e6-b784-5033db27bef2" begin + function check_species_validity(::Mangal.MangalReferenceTaxon) + end + function check_species_validity(::Mangal.MangalNode) + end + end + @require GBIF="ee291a33-5a6c-5552-a3c8-0f29a1181037" begin + function check_species_validity(::GBIF.GBIFTaxon) + end + end end # General useful manipulations @@ -147,6 +154,9 @@ export KGL01, KGL02, KGL03, KGL04, KGL05, KGL06, KGL07, KGL08, KGL09, KGL10, include(joinpath(".", "foodwebs/trophiclevels.jl")) export fractional_trophic_level, trophic_level +include(joinpath(".", "foodwebs/omnivory.jl")) +export omnivory + include(joinpath(".", "information/entropy.jl")) export entropy, make_joint_distribution, mutual_information, conditional_entropy, variation_information, diff_entropy_uniform, information_decomposition, diff --git a/src/foodwebs/omnivory.jl b/src/foodwebs/omnivory.jl new file mode 100644 index 000000000..9f6ee28e1 --- /dev/null +++ b/src/foodwebs/omnivory.jl @@ -0,0 +1,24 @@ +function omnivory(N::T) where {T <: UnipartiteNetwork} + OI = Dict([s => 0.0 for s in species(N)]) + + TL = fractional_trophic_level(N) + k = degree(N; dims=1) + + for sp_i in species(N) + + # Species with no interaction have an omnivory index of 0 + k[sp_i] > 0 || continue + + # For every species, we set its initial omnivory to 0 + oi = 0.0 + for (j, sp_j) in enumerate(species(N)) + # Then for every species it consumes, we ha + tl_diff = (TL[sp_j] - (TL[sp_i]-1.0)).^2.0 + corr = N[sp_i,sp_j]/k[sp_i] + oi += tl_diff * corr + end + OI[sp_i] = oi + end + + return OI +end diff --git a/src/types/constructors.jl b/src/types/constructors.jl index d6477e764..792f9c73e 100644 --- a/src/types/constructors.jl +++ b/src/types/constructors.jl @@ -5,7 +5,7 @@ function UnipartiteNetwork(A::M) where {M<:AbstractMatrix{Bool}} end function UnipartiteNetwork(A::M, S::Vector{NT}) where {M<:AbstractMatrix{Bool}, NT} - is_valid_species($1) || throw(ArgumentError("$(NT) is not a valid type of node")) + check_species_validity(NT) check_unipartiteness(A, S) UnipartiteNetwork{Bool,NT}(A, S) end @@ -18,7 +18,7 @@ function BipartiteNetwork(A::M) where {M<:AbstractMatrix{Bool}} end function BipartiteNetwork(A::M, T::Vector{NT}, B::Vector{NT}) where {M<:AbstractMatrix{Bool}, NT} - is_valid_species($1) || throw(ArgumentError("$(NT) is not a valid type of node")) + check_species_validity(NT) check_bipartiteness(A, T, B) BipartiteNetwork{Bool,eltype(T)}(A, T, B) end @@ -32,7 +32,7 @@ function BipartiteProbabilisticNetwork(A::Matrix{IT}) where {IT<:AbstractFloat} end function BipartiteProbabilisticNetwork(A::Matrix{IT}, T::Vector{NT}, B::Vector{NT}) where {IT<:AbstractFloat, NT} - is_valid_species($1) || throw(ArgumentError("$(NT) is not a valid type of node")) + check_species_validity(NT) check_bipartiteness(A, T, B) check_probability_values(A) BipartiteProbabilisticNetwork{IT,NT}(A, T, B) @@ -46,7 +46,7 @@ function BipartiteQuantitativeNetwork(A::Matrix{IT}) where {IT <: Number} end function BipartiteQuantitativeNetwork(A::Matrix{IT}, T::Vector{NT}, B::Vector{NT}) where {IT<:Number,NT} - is_valid_species($1) || throw(ArgumentError("$(NT) is not a valid type of node")) + check_species_validity(NT) check_bipartiteness(A, T, B) BipartiteQuantitativeNetwork{IT,NT}(A, T, B) end @@ -58,7 +58,7 @@ function UnipartiteQuantitativeNetwork(A::Matrix{IT}) where {IT<:Number} end function UnipartiteQuantitativeNetwork(A::Matrix{IT}, S::Vector{NT}) where {IT<:Number,NT} - is_valid_species($1) || throw(ArgumentError("$(NT) is not a valid type of node")) + check_species_validity(NT) check_unipartiteness(A, S) UnipartiteQuantitativeNetwork{IT,NT}(A, S) end @@ -73,7 +73,7 @@ function UnipartiteProbabilisticNetwork(A::Matrix{IT}) where {IT<:AbstractFloat} end function UnipartiteProbabilisticNetwork(A::Matrix{IT}, S::Vector{NT}) where {IT<:AbstractFloat,NT} - is_valid_species($1) || throw(ArgumentError("$(NT) is not a valid type of node")) + check_species_validity(NT) check_unipartiteness(A, S) check_probability_values(A) UnipartiteProbabilisticNetwork{IT,NT}(A, S) diff --git a/src/types/utilities.jl b/src/types/utilities.jl index 0920cabba..3c6ea9c87 100644 --- a/src/types/utilities.jl +++ b/src/types/utilities.jl @@ -1,8 +1,11 @@ import Base: getindex, setindex!, permutedims, permutedims!, size, copy, !, show, +, inv, similar -is_valid_species(::Type{T}) where {T <: Any} = false +function check_species_validity(::Type{T}) where {T <: Any} + throw(ArgumentError("The type $(T) is not an allowed species type")) +end -is_valid_species(::Type{T}) where {T <: Union{Symbol,String}} = true +function check_species_validity(::Type{T}) where {T <: Union{Symbol,String}} +end """ show(io::IO, N::AbstractEcologicalNetwork) @@ -70,7 +73,7 @@ for the presence of an interaction. Use `N[i,j]` if you need to get the value of the interaction. """ function has_interaction(N::AbstractEcologicalNetwork, i::NT, j::NT) where {NT} - @assert is_valid_species(NT) + check_species_validity(NT) @assert i ∈ species(N; dims=1) @assert j ∈ species(N; dims=2) i_pos = something(findfirst(isequal(i), species(N; dims=1)),0)