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

human-readable output for simple graphs #148

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
66 changes: 64 additions & 2 deletions src/SimpleGraphs/SimpleGraphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ using Graphs
using SimpleTraits

import Base:
eltype, show, ==, Pair, Tuple, copy, length, issubset, reverse, zero, in, iterate
eltype, show, summary, ==, Pair, Tuple, copy, length, issubset, reverse, zero, in, iterate

import Graphs:
_NI, AbstractGraph, AbstractEdge, AbstractEdgeIter,
Expand Down Expand Up @@ -50,11 +50,73 @@ An abstract type representing a simple graph structure.
"""
abstract type AbstractSimpleGraph{T<:Integer} <: AbstractGraph{T} end

function show(io::IO, ::MIME"text/plain", g::AbstractSimpleGraph{T}) where T
function summary(io::IO, @nospecialize(g::AbstractSimpleGraph{T})) where T
dir = is_directed(g) ? "directed" : "undirected"
print(io, "{$(nv(g)), $(ne(g))} $dir simple $T graph")
end

object_width(io, x) = textwidth(sprint(print, x, context=io, sizehint=0))

function _print_outneighbors(io, @nospecialize(X::AbstractVecOrMat))
s = sprint(show, X, context=io, sizehint=0)
return match(r"(\[.*)", s).match # remove type when vertex type is different from Int64
end


function _print_rows(io, g, rows, lastindx, arrow, max_vertex_size)
for i in rows
print(io, " "^(max_vertex_size - object_width(io, i)))
print(io, i)
print(io, arrow)
s = _print_outneighbors(io, outneighbors(g, i))
if i != lastindx
println(io, s)
else
print(io, s)
end
end
end

function _print_graph(io, @nospecialize(g::AbstractSimpleGraph{T})) where T
if !(get(io, :limit, false)::Bool)
screenheight = typemax(Int)
else
sz = displaysize(io)::Tuple{Int,Int}
screenheight = sz[1] - 4
end
vdots = "\u22ee"
arrow = " => "
max_vertex_size = object_width(io, nv(g))
halfheight = div(screenheight,2)
lastindx = nv(g)
if nv(g) > screenheight
rowsA, rowsB = 1:halfheight, lastindx-div(screenheight-1,2)+1:lastindx
else
rowsA, rowsB = 1:lastindx, 1:0
end

_print_rows(io, g, rowsA, nv(g), arrow, max_vertex_size)
if last(rowsA) != lastindx
print(io, " "^(max_vertex_size - length(vdots)))
print(io, vdots)
if !isempty(rowsB)
println(io)
end
_print_rows(io, g, rowsB, lastindx, arrow, max_vertex_size)
end
end

function show(io::IO, ::MIME"text/plain", @nospecialize(g::AbstractSimpleGraph{T})) where T
summary(io, g)
if get(io, :limit, false) && displaysize(io)[1]-4 <= 0
return print(io, " …")
elseif nv(g) > 0
println(io)
_print_graph(io, g)
end
end


nv(g::AbstractSimpleGraph{T}) where T = T(length(fadj(g)))
vertices(g::AbstractSimpleGraph) = Base.OneTo(nv(g))

Expand Down
16 changes: 8 additions & 8 deletions test/simplegraphs/simplegraphs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,15 @@ import Random
T = eltype(g)
@test repr("text/plain", g) == "{0, 0} undirected simple $T graph"
@test @inferred(add_vertices!(g, 5) == 5)
@test repr("text/plain", g) == "{5, 0} undirected simple $T graph"
@test repr("text/plain", g) == "{5, 0} undirected simple $T graph\n1 => []\n2 => []\n3 => []\n4 => []\n5 => []"
@test eval(Meta.parse(repr(g))) == g
end
gx = SimpleDiGraph()
for g in testdigraphs(gx)
T = eltype(g)
@test repr("text/plain", g) == "{0, 0} directed simple $T graph"
@test @inferred(add_vertices!(g, 5) == 5)
@test repr("text/plain", g) == "{5, 0} directed simple $T graph"
@test repr("text/plain", g) == "{5, 0} directed simple $T graph\n1 => []\n2 => []\n3 => []\n4 => []\n5 => []"
@test eval(Meta.parse(repr(g))) == g
end

Expand Down Expand Up @@ -232,7 +232,7 @@ import Random
edge_set_any = Set{Any}(edge_list)

g1 = @inferred SimpleGraph(edge_list)
# we can't infer the return type of SimpleGraphFromIterator at the moment
# we can't infer the return type of SimpleGraphFromIterator at the moment
g2 = SimpleGraphFromIterator(edge_list)
g3 = SimpleGraphFromIterator(edge_iter)
g4 = SimpleGraphFromIterator(edge_set)
Expand All @@ -258,13 +258,13 @@ import Random
# We create an edge list and shuffle it
edge_list = [e for e in edges(g)]
shuffle!(MersenneTwister(0), edge_list)

edge_iter = (e for e in edge_list)
edge_set = Set(edge_list)
edge_set_any = Set{Any}(edge_list)

g1 = @inferred SimpleDiGraph(edge_list)
# we can't infer the return type of SimpleDiGraphFromIterator at the moment
# we can't infer the return type of SimpleDiGraphFromIterator at the moment
g2 = SimpleDiGraphFromIterator(edge_list)
g3 = SimpleDiGraphFromIterator(edge_iter)
g4 = SimpleDiGraphFromIterator(edge_set)
Expand Down Expand Up @@ -302,7 +302,7 @@ import Random
@test_throws DomainError SimpleDiGraphFromIterator( (SimpleDiGraphEdge(1,2), "a string") )
end

# check if multiple edges && multiple self-loops result in the
# check if multiple edges && multiple self-loops result in the
# correct number of edges & vertices
# edges using integers < 1 should be ignored
g_undir = SimpleGraph(0)
Expand All @@ -325,7 +325,7 @@ import Random
@test nv(g3) == 4
@test nv(g4) == 4
@test nv(g5) == 4

@test ne(g1) == 2
@test ne(g2) == 2
@test ne(g3) == 2
Expand All @@ -352,7 +352,7 @@ import Random
@test nv(g3) == 4
@test nv(g4) == 4
@test nv(g5) == 4

@test ne(g1) == 3
@test ne(g2) == 3
@test ne(g3) == 3
Expand Down