Skip to content

Formats outside @require + Package extensions #51

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

Merged
merged 6 commits into from
Jun 23, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Formats outside @require
  • Loading branch information
filchristou committed Jan 10, 2023
commit c655409418305bf00fc086846583a7df07e7daec
77 changes: 4 additions & 73 deletions src/DOT/Dot.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module DOT

using GraphIO.ParserCombinator.Parsers
using Requires
using Graphs
using Graphs: AbstractGraphFormat

Expand All @@ -10,79 +10,10 @@ export DOTFormat

struct DOTFormat <: AbstractGraphFormat end

function savedot(io::IO, g::Graphs.AbstractGraph, gname::String = "")
isdir = Graphs.is_directed(g)
println(io,(isdir ? "digraph " : "graph ") * gname * " {")
for i in Graphs.vertices(g)
println(io,"\t" * string(i))
function __init__()
@require ParserCombinator="fae87a5f-d1ad-5cf0-8f61-c941e1580b46" begin
include("Dot_conditional.jl")
end
if isdir
for u in Graphs.vertices(g)
out_nbrs = Graphs.outneighbors(g, u)
length(out_nbrs) == 0 && continue
println(io, "\t" * string(u) * " -> {" * join(out_nbrs,',') * "}")
end
else
for e in Graphs.edges(g)
source = string(Graphs.src(e))
dest = string(Graphs.dst(e))
println(io, "\t" * source * " -- " * dest)
end
end
println(io,"}")
return 1
end

function savedot_mult(io::IO, graphs::Dict)
ng = 0
for (gname, g) in graphs
ng += savedot(io, g, gname)
end
return ng
end

function _dot_read_one_graph(pg::Parsers.DOT.Graph)
isdir = pg.directed
nvg = length(Parsers.DOT.nodes(pg))
nodedict = Dict(zip(collect(Parsers.DOT.nodes(pg)), 1:nvg))
if isdir
g = Graphs.DiGraph(nvg)
else
g = Graphs.Graph(nvg)
end
for es in Parsers.DOT.edges(pg)
s = nodedict[es[1]]
d = nodedict[es[2]]
add_edge!(g, s, d)
end
return g
end

_name(pg::Parsers.DOT.Graph) =
pg.id !== nothing ? pg.id.id :
Parsers.DOT.StringID(pg.directed ? "digraph" : "graph")

function loaddot(io::IO, gname::String)
p = Parsers.DOT.parse_dot(read(io, String))
for pg in p
_name(pg) == gname && return _dot_read_one_graph(pg)
end
error("Graph $gname not found")
end

function loaddot_mult(io::IO)
p = Parsers.DOT.parse_dot(read(io, String))
graphs = Dict{String,AbstractGraph}()

for pg in p
graphs[_name(pg)] = _dot_read_one_graph(pg)
end
return graphs
end

loadgraph(io::IO, gname::String, ::DOTFormat) = loaddot(io, gname)
loadgraphs(io::IO, ::DOTFormat) = loaddot_mult(io)
savegraph(io::IO, g::AbstractGraph, gname::String, ::DOTFormat) = savedot(io, g, gname)
savegraph(io::IO, d::Dict, ::DOTFormat) = savedot_mult(io, d)

end #module
76 changes: 76 additions & 0 deletions src/DOT/Dot_conditional.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using .ParserCombinator.Parsers

function savedot(io::IO, g::Graphs.AbstractGraph, gname::String = "")
isdir = Graphs.is_directed(g)
println(io,(isdir ? "digraph " : "graph ") * gname * " {")
for i in Graphs.vertices(g)
println(io,"\t" * string(i))
end
if isdir
for u in Graphs.vertices(g)
out_nbrs = Graphs.outneighbors(g, u)
length(out_nbrs) == 0 && continue
println(io, "\t" * string(u) * " -> {" * join(out_nbrs,',') * "}")
end
else
for e in Graphs.edges(g)
source = string(Graphs.src(e))
dest = string(Graphs.dst(e))
println(io, "\t" * source * " -- " * dest)
end
end
println(io,"}")
return 1
end

function savedot_mult(io::IO, graphs::Dict)
ng = 0
for (gname, g) in graphs
ng += savedot(io, g, gname)
end
return ng
end

function _dot_read_one_graph(pg::Parsers.DOT.Graph)
isdir = pg.directed
nvg = length(Parsers.DOT.nodes(pg))
nodedict = Dict(zip(collect(Parsers.DOT.nodes(pg)), 1:nvg))
if isdir
g = Graphs.DiGraph(nvg)
else
g = Graphs.Graph(nvg)
end
for es in Parsers.DOT.edges(pg)
s = nodedict[es[1]]
d = nodedict[es[2]]
add_edge!(g, s, d)
end
return g
end

_name(pg::Parsers.DOT.Graph) =
pg.id !== nothing ? pg.id.id :
Parsers.DOT.StringID(pg.directed ? "digraph" : "graph")

function loaddot(io::IO, gname::String)
p = Parsers.DOT.parse_dot(read(io, String))
for pg in p
_name(pg) == gname && return _dot_read_one_graph(pg)
end
error("Graph $gname not found")
end

function loaddot_mult(io::IO)
p = Parsers.DOT.parse_dot(read(io, String))
graphs = Dict{String,AbstractGraph}()

for pg in p
graphs[_name(pg)] = _dot_read_one_graph(pg)
end
return graphs
end

loadgraph(io::IO, gname::String, ::DOTFormat) = loaddot(io, gname)
loadgraphs(io::IO, ::DOTFormat) = loaddot_mult(io)
savegraph(io::IO, g::AbstractGraph, gname::String, ::DOTFormat) = savedot(io, g, gname)
savegraph(io::IO, d::Dict, ::DOTFormat) = savedot_mult(io, d)
43 changes: 4 additions & 39 deletions src/GEXF/Gexf.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module GEXF

using GraphIO.EzXML
using Requires
using Graphs
using Graphs: AbstractGraph, AbstractGraphFormat

Expand All @@ -10,46 +10,11 @@ export GEXFFormat

# TODO: implement readgexf
struct GEXFFormat <: AbstractGraphFormat end
"""
savegexf(f, g, gname)

Write a graph `g` with name `gname` to an IO stream `io` in the
[Gexf](http://gexf.net/format/) format. Return 1 (number of graphs written).
"""
function savegexf(io::IO, g::Graphs.AbstractGraph, gname::String)
xdoc = XMLDocument()
xroot = setroot!(xdoc, ElementNode("gexf"))
xroot["xmlns"] = "http://www.gexf.net/1.2draft"
xroot["version"] = "1.2"
xroot["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
xroot["xsi:schemaLocation"] = "http://www.gexf.net/1.2draft/gexf.xsd"

xmeta = addelement!(xroot, "meta")
addelement!(xmeta, "description", gname)
xg = addelement!(xroot, "graph")
strdir = is_directed(g) ? "directed" : "undirected"
xg["defaultedgetype"] = strdir

xnodes = addelement!(xg, "nodes")
for i in 1:nv(g)
xv = addelement!(xnodes, "node")
xv["id"] = "$(i-1)"
end

xedges = addelement!(xg, "edges")
m = 0
for e in Graphs.edges(g)
xe = addelement!(xedges, "edge")
xe["id"] = "$m"
xe["source"] = "$(src(e)-1)"
xe["target"] = "$(dst(e)-1)"
m += 1
function __init__()
@require EzXML="8f5d6c58-4d21-5cfd-889c-e3ad7ee6a615" begin
include("Gexf_conditional.jl")
end

prettyprint(io, xdoc)
return 1
end

savegraph(io::IO, g::AbstractGraph, gname::String, ::GEXFFormat) = savegexf(io, g, gname)

end #module
43 changes: 43 additions & 0 deletions src/GEXF/Gexf_conditional.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using .EzXML

"""
savegexf(f, g, gname)

Write a graph `g` with name `gname` to an IO stream `io` in the
[Gexf](http://gexf.net/format/) format. Return 1 (number of graphs written).
"""
function savegexf(io::IO, g::Graphs.AbstractGraph, gname::String)
xdoc = XMLDocument()
xroot = setroot!(xdoc, ElementNode("gexf"))
xroot["xmlns"] = "http://www.gexf.net/1.2draft"
xroot["version"] = "1.2"
xroot["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
xroot["xsi:schemaLocation"] = "http://www.gexf.net/1.2draft/gexf.xsd"

xmeta = addelement!(xroot, "meta")
addelement!(xmeta, "description", gname)
xg = addelement!(xroot, "graph")
strdir = is_directed(g) ? "directed" : "undirected"
xg["defaultedgetype"] = strdir

xnodes = addelement!(xg, "nodes")
for i in 1:nv(g)
xv = addelement!(xnodes, "node")
xv["id"] = "$(i-1)"
end

xedges = addelement!(xg, "edges")
m = 0
for e in Graphs.edges(g)
xe = addelement!(xedges, "edge")
xe["id"] = "$m"
xe["source"] = "$(src(e)-1)"
xe["target"] = "$(dst(e)-1)"
m += 1
end

prettyprint(io, xdoc)
return 1
end

savegraph(io::IO, g::AbstractGraph, gname::String, ::GEXFFormat) = savegexf(io, g, gname)
89 changes: 4 additions & 85 deletions src/GML/Gml.jl
Original file line number Diff line number Diff line change
@@ -1,100 +1,19 @@
module GML

using GraphIO.ParserCombinator.Parsers
using Requires
using Graphs
using Graphs: AbstractGraphFormat

import Graphs: loadgraph, loadgraphs, savegraph

export GMLFormat


struct GMLFormat <: AbstractGraphFormat end

function _gml_read_one_graph(gs, dir)
nodes = [x[:id] for x in gs[:node]]
if dir
g = Graphs.DiGraph(length(nodes))
else
g = Graphs.Graph(length(nodes))
end
mapping = Dict{Int,Int}()
for (i, n) in enumerate(nodes)
mapping[n] = i
end
sds = [(Int(x[:source]), Int(x[:target])) for x in gs[:edge]]
for (s, d) in (sds)
add_edge!(g, mapping[s], mapping[d])
end
return g
end

function loadgml(io::IO, gname::String)
p = Parsers.GML.parse_dict(read(io, String))
for gs in p[:graph]
dir = Bool(get(gs, :directed, 0))
graphname = get(gs, :label, dir ? "digraph" : "graph")

(gname == graphname) && return _gml_read_one_graph(gs, dir)
end
error("Graph $gname not found")
end

function loadgml_mult(io::IO)
p = Parsers.GML.parse_dict(read(io, String))
graphs = Dict{String,Graphs.AbstractGraph}()
for gs in p[:graph]
dir = Bool(get(gs, :directed, 0))
graphname = get(gs, :label, dir ? "digraph" : "graph")
graphs[graphname] = _gml_read_one_graph(gs, dir)
end
return graphs
end

"""
savegml(f, g, gname="graph")

Write a graph `g` with name `gname` to an IO stream `io` in the
[GML](https://en.wikipedia.org/wiki/Graph_Modelling_Language) format. Return 1.
"""
function savegml(io::IO, g::Graphs.AbstractGraph, gname::String = "")
println(io, "graph")
println(io, "[")
length(gname) > 0 && println(io, "label \"$gname\"")
is_directed(g) && println(io, "directed 1")
for i = 1:nv(g)
println(io, "\tnode")
println(io, "\t[")
println(io, "\t\tid $i")
println(io, "\t]")
end
for e in Graphs.edges(g)
s, t = Tuple(e)
println(io, "\tedge")
println(io, "\t[")
println(io, "\t\tsource $s")
println(io, "\t\ttarget $t")
println(io, "\t]")
end
println(io, "]")
return 1
end


"""
savegml_mult(io, graphs)
Write a dictionary of (name=>graph) to an IO stream `io` Return number of graphs written.
"""
function savegml_mult(io::IO, graphs::Dict)
ng = 0
for (gname, g) in graphs
ng += savegml(io, g, gname)
function __init__()
@require ParserCombinator="fae87a5f-d1ad-5cf0-8f61-c941e1580b46" begin
include("Gml_conditional.jl")
end
return ng
end
loadgraph(io::IO, gname::String, ::GMLFormat) = loadgml(io, gname)
loadgraphs(io::IO, ::GMLFormat) = loadgml_mult(io)
savegraph(io::IO, g::AbstractGraph, gname::String, ::GMLFormat) = savegml(io, g, gname)
savegraph(io::IO, d::Dict, ::GMLFormat) = savegml_mult(io, d)

end # module
Loading