Skip to content
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@

.ipynb_checkpoints
.ipynb_checkpoints/*

.CondaPkg

.DS_Store
8 changes: 8 additions & 0 deletions CondaPkg.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[deps]
networkx = ""
matplotlib = ""
pandas = "<2.3"

[pip.deps]
hypernetx = ">=2.4.0,<3"
fastjsonschema = ""
18 changes: 9 additions & 9 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
name = "SimpleHypergraphs"
uuid = "aa4a32ff-dd5d-5357-90e3-e7a9512f0501"
version = "0.3.4"
authors = ["Przemysław Szufel <pszufe@sgh.waw.pl>", "Bogumił Kamiński <bkamins@sgh.waw.pl>", "Carmine Spagnuolo <spagnuolocarmine@gmail.com>", "Alessia Antelmi <aless.antelmi@gmail.com>", "Evan Walter Clark Spotte-Smith <espottesmith@gmail.com>"]
authors = ["Przemysław Szufel <pszufe@sgh.waw.pl>", "Bogumił Kamiński <bkamins@sgh.waw.pl>", "Carmine Spagnuolo <spagnuolocarmine@gmail.com>", "Alessia Antelmi <aless.antelmi@gmail.com>", "Evan Walter Clark Spotte-Smith <espottesmith@gmail.com>", "Daniele De Vinco <ddevinco@unisa.it>"]
version = "0.4.0"

[deps]
Conda = "8f4d0f93-b110-5947-807f-2305c1781a2d"
CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee"
PythonCall = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
PythonPlot = "274fc56d-3b97-40fa-a1cd-1b4a50311bf9"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SimpleTraits = "699a6c99-e7fa-54fc-8d76-47d257e15c1d"
SparseArrays = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
StructTypes = "856f2bd8-1eba-4b0a-8007-ebc267875bd4"

[compat]
Conda = "^1.5.0"
CondaPkg = "^0.2"
DataFrames = "^1.7.0"
DataStructures = "^0.18.11, ^0.19.1"
Graphs = "^1.4.1"
JSON = "^1.0.0"
PyCall = "^1.91.2"
PyPlot = "^2.8.2"
JSON = "^1.3.0"
PythonCall = "^0.9"
PythonPlot = "^1.0"
SimpleTraits = "^0.9.4"
SparseArrays = "^1.0.0"
StatsBase = "^0.34.0"
Expand Down
31 changes: 20 additions & 11 deletions src/SimpleHypergraphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ using Graphs
using StatsBase
using DataStructures
using DataFrames
using PyCall
using Conda
using PyPlot
using PythonCall
using CondaPkg
using PythonPlot
using JSON
using Random
using LinearAlgebra
Expand Down Expand Up @@ -48,28 +48,37 @@ export distance
export HyperNetX, GraphBased
export draw

const hnx = PyNULL()
const nx = PyNULL()
const hnx = Ref{Py}()
const nx = Ref{Py}()
const pyplot = Ref{Py}()
const has_plotting = Ref(false)


function __init__()
has_networkx = false
has_hypernetx = false
has_pyplot = false
try
copy!(nx, pyimport("networkx"))
nx[] = pyimport("networkx")
has_networkx = true
catch e; end
try
copy!(hnx, pyimport("hypernetx"))
hnx[] = pyimport("hypernetx")
has_hypernetx = true
catch e; end
has_plotting[] = has_networkx && has_hypernetx
try
pyplot[] = pyimport("matplotlib.pyplot")
has_pyplot = true
catch e; end
has_plotting[] = has_networkx && has_hypernetx && has_pyplot
if !has_plotting[]
@warn "The plotting functionality of HyperNetX will not work!\n"*
(has_networkx ? "" : "Conda Python networkx not found.\n")*
(has_hypernetx ? "" : "Conda Python HyperNetX not found.\n")*
"To test your installation try running `using PyCall;pyimport(\"networkx\");pyimport(\"hypernetx\")`"
(has_networkx ? "" : "CondaPkg Python networkx not found.\n")*
(has_hypernetx ? "" : "CondaPkg Python HyperNetX not found.\n")*
(has_pyplot ? "" : "CondaPkg Python matplotlib.pyplot not found.\n")*
"To test your installation try running `using PythonCall;pyimport(\"networkx\");pyimport(\"hypernetx\");pyimport(\"matplotlib.pyplot\")`"
else
@info "HyperNetX plotting support loaded successfully"
end
end

Expand Down
9 changes: 6 additions & 3 deletions src/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ function hg_load(
json_hg.he_meta = JSON.parse(json_hg.he_meta)
end
m = reshape(Vector{Union{T, Nothing}}(json_hg.m), json_hg.n, json_hg.k)

V2 = (V == :auto) ? ("v_meta" ∈ keys(json_hg) && length(json_hg.v_meta) > 0 ? elemtypes(json_hg.v_meta) : Nothing) : V
E2 = (E == :auto) ? ("he_meta" ∈ keys(json_hg) && length(json_hg.he_meta) > 0 ? elemtypes(json_hg.he_meta) : Nothing) : E

Expand All @@ -253,9 +253,12 @@ end
format::Abstract_HG_format = HGF_Format(),
HType::Type{H} = Hypergraph,
T::Type{U} = Bool,
D::Type{<:AbstractDict{Int, U}} = Dict{Int, T},
V = Nothing,
E = Nothing
E = Nothing,
D::Type{<:AbstractDict{Int, U}} = Dict{Int, T},
show_warning::Bool=true,
sort_by_id::Bool=false,
add_original_id_to_meta::Union{Symbol, Nothing}=nothing
) where {U <: Real, H <: AbstractSimpleHypergraph}

Loads a hypergraph from a file `fname`.
Expand Down
57 changes: 31 additions & 26 deletions src/viz/drawing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,9 @@ end
with_color::Bool=true,
with_node_counts::Bool=false,
with_edge_counts::Bool=false,
layout::PyObject=nx.spring_layout,
layout::Py=nx[],
layout_kwargs::Dict=Dict{String, Any}(),
ax::Union{PyObject, Nothing}=nothing,
ax::Union{Py, Nothing}=nothing,
no_border::Bool=false,
edges_kwargs::Dict=Dict{String, Any}(),
nodes_kwargs::Dict=Dict{String, Any}(),
Expand Down Expand Up @@ -194,21 +194,20 @@ function draw(
edge_labels::Union{Dict{Int, String}, Nothing}=nothing,
collapse_nodes::Bool=false,
collapse_edges::Bool=false,
node_radius::Union{Int, Nothing}=nothing,
pos::Union{Dict{Int,Pair{Int,Int}}, Nothing}=nothing,
with_color::Bool=true,
with_node_counts::Bool=false,
with_edge_counts::Bool=false,
layout::PyObject=nx.spring_layout,
layout::Py=nx[].spring_layout,
layout_kwargs::Dict=Dict{String, Any}(),
ax::Union{PyObject, Nothing}=nothing,
ax::Union{Py, Nothing}=nothing,
no_border::Bool=false,
edges_kwargs::Dict=Dict{String, Any}(),
nodes_kwargs::Dict=Dict{String, Any}(),
edge_labels_kwargs::Dict=Dict{String, Any}(),
node_labels_kwargs::Dict=Dict{String, Any}(),
with_edge_labels::Bool=true,
with_node_labels::Bool=true,
label_alpha::Float64=.35
node_label_alpha::Float64=.35,
edge_label_alpha::Float64=.35
) where {H<:AbstractSimpleHypergraph}
if (!SimpleHypergraphs.support_hypernetx())
throw("HyperNetX is not installed in Python used by this Julia. Install HyperNetX and reload SimpleHypergraphs.jl")
Expand All @@ -227,30 +226,31 @@ function draw(
end

if ax === nothing #isnothing(ax)
fig = plt.figure(figsize=[width,height])
ax = plt.gca()
fig = pyplot[].figure(figsize=[width,height])
ax = pyplot[].gca()

if no_border
ax.axis("off")
end
end

hnx.draw(h_hnx,
hnx[].draw(h_hnx,
pos=pos,
with_color=with_color,
with_node_counts=with_node_counts,
with_edge_counts=with_edge_counts,
layout=layout,
layout_kwargs=layout_kwargs,
ax=ax,
node_radius=node_radius,
edges_kwargs=edges_kwargs,
nodes_kwargs=nodes_kwargs,
edge_labels_kwargs=edge_labels_kwargs,
node_labels_kwargs=node_labels_kwargs,
with_edge_labels=with_edge_labels,
with_node_labels=with_node_labels,
label_alpha=label_alpha
node_label_alpha=node_label_alpha,
edge_label_alpha=edge_label_alpha
)

return pyplot[].gcf()
end


Expand All @@ -271,23 +271,28 @@ function _convert_to_hnx(h::Hypergraph;
node_labels::Union{Dict{Int, String}, Nothing}=nothing,
edge_labels::Union{Dict{Int, String}, Nothing}=nothing,
)
h_hnx = hnx.Hypergraph()
pybuiltins = pyimport("builtins")
edges_dict = pybuiltins.dict()

for he=1:nhe(h)
if node_labels === nothing #isnothing(node_labels)
vertices = collect(keys(getvertices(h, he)))
vertices = collect(keys(getvertices(h, he)))

if node_labels === nothing
vertices = [string(v) for v in vertices]
else
vertices = [get(node_labels, v, v) for v in collect(keys(getvertices(h, he)))]
vertices = [get(node_labels, v, string(v)) for v in vertices]
end

if edge_labels === nothing #isnothing(edge_labels)
he_hnx = hnx.Entity(string(he), elements=vertices)
edge_label = if edge_labels === nothing
string(he)
else
he_hnx = hnx.Entity(get(edge_labels, he, string(he)), elements=vertices)
get(edge_labels, he, string(he))
end

h_hnx.add_edge(he_hnx)
edges_dict[edge_label] = pybuiltins.list(vertices)
end


h_hnx = hnx[].Hypergraph(edges_dict)

h_hnx
end
115 changes: 115 additions & 0 deletions test/hif-standard-tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,121 @@ end
end
end


@testset "Tutorials JSON Data " begin
pth = joinpath(dirname(dirname(pathof(SimpleHypergraphs))), "tutorials", "basics", "data");
pth2 = joinpath(dirname(dirname(pathof(SimpleHypergraphs))), "tutorials", "hif-standard", "data");
files = String[]
for (root, dirs, filenames) in walkdir(pth)
for file in filenames
if endswith(file, ".json")
if contains(file, "hif.json")
continue
end
push!(files, joinpath(root, file))
end
end
end
for (root, dirs, filenames) in walkdir(pth2)
for file in filenames
if endswith(file, ".json")
if contains(file, "hif.json")
continue
end
push!(files, joinpath(root, file))
end
end
end
for file in files
println("Testing tutorials JSON file: $(basename(file))")

flush(stdout)
flush(stderr)
if !endswith(file, "hg_seasons_min.json")
loaded_hg = hg_load(file; format=JSON_Format(), HType=Hypergraph, T=Bool, V=Symbol, E=Symbol)
else
loaded_hg = hg_load(file; format=JSON_Format(), HType=Hypergraph, T=Int, V=Symbol, E=Symbol)
end
io_h = IOBuffer()
hg_save(io_h, loaded_hg, JSON_Format(); pretty=true)
if !endswith(file, "hg_seasons_min.json")
h_loaded = hg_load(seekstart(io_h), JSON_Format(); HType=Hypergraph, T=Bool, V=Symbol, E=Symbol)
else
h_loaded = hg_load(seekstart(io_h), JSON_Format(); HType=Hypergraph, T=Int, V=Symbol, E=Symbol)
end
@test loaded_hg == h_loaded
end

end;

@testset "Tutorials as HIF Data " begin
pth = joinpath(dirname(dirname(pathof(SimpleHypergraphs))), "tutorials", "basics", "data");
pth2 = joinpath(dirname(dirname(pathof(SimpleHypergraphs))), "tutorials", "hif-standard", "data");
files = String[]
for (root, dirs, filenames) in walkdir(pth)
for file in filenames
if endswith(file, "hif.json")
push!(files, joinpath(root, file))
end
end
end
for (root, dirs, filenames) in walkdir(pth2)
for file in filenames
if endswith(file, "hif.json")
push!(files, joinpath(root, file))
end
end
end
for file in files
println("Testing tutorials as HIF file: $(basename(file))")
flush(stdout)
flush(stderr)
if !endswith(file, "hg_seasons_min.json")
loaded_hg = hg_load(
file;
format=HIF_Format(),
HType=Hypergraph,
T=Bool, V=:auto, E=:auto
)
else
loaded_hg = hg_load(
file;
format=HIF_Format(),
HType=Hypergraph,
T=Int, V=:auto, E=:auto
)
end
io_h = IOBuffer()
hg_save(io_h, loaded_hg, HIF_Format(); pretty=true)

if !endswith(file, "hg_seasons_min.json")
h_loaded = hg_load(seekstart(io_h), HIF_Format(); HType=Hypergraph, T=Bool, V=:auto, E=:auto)
else
h_loaded = hg_load(seekstart(io_h), HIF_Format(); HType=Hypergraph, T=Int, V=:auto, E=:auto)
end

@test loaded_hg == h_loaded
end

end;

@testset "JSON and HIF correct load test" begin
path = joinpath(dirname(dirname(pathof(SimpleHypergraphs))), "tutorials", "basics", "data", "hg_seasons_min.json");

h1 = SimpleHypergraphs.hg_load(
path; format=JSON_Format(), HType=Hypergraph, T=Int, V=:auto, E=:auto
)

@test nhv(h1) == 149
@test nhe(h1) == 8

pth_hif = joinpath(dirname(dirname(pathof(SimpleHypergraphs))), "tutorials", "basics", "data", "hg_seasons_min.hif.json")
h2 = SimpleHypergraphs.hg_load(pth_hif; format=HIF_Format(), T=Int, V=:auto, E=:auto)

@test nhv(h2) == 149
@test nhe(h2) == 8
end

#==
using Revise
using SimpleHypergraphs
Expand Down
Loading
Loading