diff --git a/src/lines.jl b/src/lines.jl index 4589641..aaa95fc 100644 --- a/src/lines.jl +++ b/src/lines.jl @@ -1,7 +1,24 @@ +function hasReverseEdge(g, e) + return has_edge(g,dst(e),src(e)) +end + +function filterUndef(array) + result = [] + for i in 1:length(array) + if isassigned(array,i) + if result == [] + result = typeof(array[i])[] + end + push!(result,array[i]) + end + end + return result +end + """ Return lines and arrow heads """ -function graphline(g, locs_x, locs_y, nodesize::Vector{T}, arrowlength, angleoffset) where {T<:Real} +function graphline(g, locs_x, locs_y, nodesize::Vector{T}, arrowlength, angleoffset, chainGraph) where {T<:Real} lines = Array{Vector{Tuple{Float64,Float64}}}(undef, ne(g)) arrows = Array{Vector{Tuple{Float64,Float64}}}(undef, ne(g)) for (e_idx, e) in enumerate(edges(g)) @@ -15,13 +32,21 @@ function graphline(g, locs_x, locs_y, nodesize::Vector{T}, arrowlength, angleoff endx = locs_x[j] + nodesize[j]*cos(θ+π) endy = locs_y[j] + nodesize[j]*sin(θ+π) lines[e_idx] = [(startx, starty), (endx, endy)] - arr1, arr2 = arrowcoords(θ, endx, endy, arrowlength, angleoffset) - arrows[e_idx] = [arr1, (endx, endy), arr2] + if chainGraph + if !hasReverseEdge(g,e) + arr1, arr2 = arrowcoords(θ, endx, endy, arrowlength, angleoffset) + arrows[e_idx] = [arr1, (endx, endy), arr2] + end + else + arr1, arr2 = arrowcoords(θ, endx, endy, arrowlength, angleoffset) + arrows[e_idx] = [arr1, (endx, endy), arr2] + end end + arrows = chainGraph ? filterUndef(arrows) : arrows lines, arrows end -function graphline(g::AbstractGraph{T}, locs_x, locs_y, nodesize::Real, arrowlength, angleoffset) where {T<:Integer} +function graphline(g::AbstractGraph{T}, locs_x, locs_y, nodesize::Real, arrowlength, angleoffset, chainGraph) where {T<:Integer} lines = Array{Vector{Tuple{Float64,Float64}}}(undef, ne(g)) arrows = Array{Vector{Tuple{Float64,Float64}}}(undef, ne(g)) for (e_idx, e) in enumerate(edges(g)) @@ -35,9 +60,17 @@ function graphline(g::AbstractGraph{T}, locs_x, locs_y, nodesize::Real, arrowlen endx = locs_x[j] + nodesize*cos(θ+π) endy = locs_y[j] + nodesize*sin(θ+π) lines[e_idx] = [(startx, starty), (endx, endy)] - arr1, arr2 = arrowcoords(θ, endx, endy, arrowlength, angleoffset) - arrows[e_idx] = [arr1, (endx, endy), arr2] + if chainGraph + if !hasReverseEdge(g,e) + arr1, arr2 = arrowcoords(θ, endx, endy, arrowlength, angleoffset) + arrows[e_idx] = [arr1, (endx, endy), arr2] + end + else + arr1, arr2 = arrowcoords(θ, endx, endy, arrowlength, angleoffset) + arrows[e_idx] = [arr1, (endx, endy), arr2] + end end + arrows = chainGraph ? filterUndef(arrows) : arrows lines, arrows end diff --git a/src/plot.jl b/src/plot.jl index 73b34a8..c698cba 100644 --- a/src/plot.jl +++ b/src/plot.jl @@ -84,6 +84,8 @@ Equal to 0 for undirected graphs. Default: `0.1` for the directed graphs `arrowangleoffset` Optional. Angular width in radians for the arrows. Default: `π/9 (20 degrees)` +`chainGraph` +Optional. Hides arrows for bidirectional edges in a directed graph. Default: false """ function gplot(g::AbstractGraph{T}, locs_x_in::Vector{R}, locs_y_in::Vector{R}; @@ -110,6 +112,7 @@ function gplot(g::AbstractGraph{T}, arrowlengthfrac = is_directed(g) ? 0.1 : 0.0, arrowangleoffset = π / 9.0, linetype = "straight", + chainGraph = false, outangle = pi/5) where {T <:Integer, R <: Real} length(locs_x_in) != length(locs_y_in) && error("Vectors must be same length") @@ -204,7 +207,7 @@ function gplot(g::AbstractGraph{T}, end else if arrowlengthfrac > 0.0 - lines_cord, arrows_cord = graphline(g, locs_x, locs_y, nodesize, arrowlengthfrac, arrowangleoffset) + lines_cord, arrows_cord = graphline(g, locs_x, locs_y, nodesize, arrowlengthfrac, arrowangleoffset, chainGraph) lines = line(lines_cord) arrows = line(arrows_cord) else diff --git a/test/data/chainGraphFalse.png b/test/data/chainGraphFalse.png new file mode 100644 index 0000000..7c19a2d Binary files /dev/null and b/test/data/chainGraphFalse.png differ diff --git a/test/data/chainGraphSizeFalse.png b/test/data/chainGraphSizeFalse.png new file mode 100644 index 0000000..53943bb Binary files /dev/null and b/test/data/chainGraphSizeFalse.png differ diff --git a/test/data/chainGraphSizeTrue.png b/test/data/chainGraphSizeTrue.png new file mode 100644 index 0000000..c9ad3b8 Binary files /dev/null and b/test/data/chainGraphSizeTrue.png differ diff --git a/test/data/chainGraphTrue.png b/test/data/chainGraphTrue.png new file mode 100644 index 0000000..8d9822b Binary files /dev/null and b/test/data/chainGraphTrue.png differ diff --git a/test/runtests.jl b/test/runtests.jl index 4c21138..5726bc5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -106,3 +106,21 @@ end @test test_images(VisualTest(plot_and_save2, refimg2), popup=!istravis) |> save_comparison |> success end + +@testset "ChainGraph" begin + g = SimpleDiGraph([ 0 1 0 1 ; 1 0 1 0 ; 1 0 0 0 ; 1 0 1 0]) + refimg1 = joinpath(datadir, "chainGraphTrue.png") + refimg2 = joinpath(datadir, "chainGraphFalse.png") + plot_and_save1(fname) = plot_and_save(fname, g, chainGraph = true) + plot_and_save2(fname) = plot_and_save(fname, g, chainGraph = false) + @test test_images(VisualTest(plot_and_save1, refimg1), popup=!istravis) |> save_comparison |> success + @test test_images(VisualTest(plot_and_save2, refimg2), popup=!istravis) |> save_comparison |> success + + g2 = SimpleDiGraph([ 0 1 0 0 0; 0 0 1 1 1; 0 1 0 1 1; 0 1 1 0 1; 0 1 1 1 0]) + refimg3 = joinpath(datadir, "chainGraphSizeTrue.png") + refimg4 = joinpath(datadir, "chainGraphSizeFalse.png") + plot_and_save3(fname) = plot_and_save(fname, g2, chainGraph=true, nodesize = [0.6; 1.0; 1.0; 1.0; 1.0]) + plot_and_save4(fname) = plot_and_save(fname, g2, chainGraph=false, nodesize = [0.6; 1.0; 1.0; 1.0; 1.0]) + @test test_images(VisualTest(plot_and_save3, refimg3), popup=!istravis) |> save_comparison |> success + @test test_images(VisualTest(plot_and_save4, refimg4), popup=!istravis) |> save_comparison |> success +end