dag_generate_digraph Function

private function dag_generate_digraph(me, rankdir, dpi) result(str)

Generate a Graphviz digraph structure for the DAG.

Example

  • To convert this to a PDF using dot: dot -Tpdf -o test.pdf test.dot, where test.dot is str written to a file.

Type Bound

dag

Arguments

Type IntentOptional Attributes Name
class(dag), intent(in) :: me
character(len=*), intent(in), optional :: rankdir

right to left orientation (e.g. 'RL')

integer(kind=ip), intent(in), optional :: dpi

resolution (e.g. 300)

Return Value character(len=:), allocatable


Calls

proc~~dag_generate_digraph~~CallsGraph proc~dag_generate_digraph dag_module::dag%dag_generate_digraph proc~integer_to_string dag_module::integer_to_string proc~dag_generate_digraph->proc~integer_to_string

Called by

proc~~dag_generate_digraph~~CalledByGraph proc~dag_generate_digraph dag_module::dag%dag_generate_digraph proc~dag_save_digraph dag_module::dag%dag_save_digraph proc~dag_save_digraph->proc~dag_generate_digraph

Source Code

    function dag_generate_digraph(me,rankdir,dpi) result(str)

    class(dag),intent(in) :: me
    character(len=:),allocatable :: str
    character(len=*),intent(in),optional :: rankdir !! right to left orientation (e.g. 'RL')
    integer(ip),intent(in),optional :: dpi !! resolution (e.g. 300)

    integer(ip) :: i,j     !! counter
    integer(ip) :: n_edges !! number of edges
    character(len=:),allocatable :: attributes !! full attributes string for node or edge
    logical :: compress !! if we can write all the edges on one line

    character(len=*),parameter :: tab = '  '              !! for indenting
    character(len=*),parameter :: newline = new_line(' ') !! line break character

    if (me%n == 0) return

    str = 'digraph G {'//newline//newline
    if (present(rankdir)) &
        str = str//tab//'rankdir='//rankdir//newline//newline
    if (present(dpi)) &
        str = str//tab//'graph [ dpi = '//integer_to_string(dpi)//' ]'//newline//newline

    ! define the vertices:
    do i=1,me%n
        attributes = get_attributes_string(me%vertices(i)%label, &
                                           me%vertices(i)%attributes)
        str = str//tab//integer_to_string(i)//' '//attributes//newline
        if (i==me%n) str = str//newline
    end do

    ! define the dependencies:
    do i=1,me%n
        if (allocated(me%vertices(i)%edges)) then
            n_edges = size(me%vertices(i)%edges)

            ! if none of the edges have attributes,
            ! then we can write them all on one line
            ! otherwise, write them line by line
            compress = .true.
            do j = 1, n_edges
                if (allocated(me%vertices(i)%edges(j)%label) .or. &
                    allocated(me%vertices(i)%edges(j)%attributes)) then
                    compress = .false.
                    exit
                end if
            end do
            if (.not. compress) then
                ! Example:   1 -> 2 [penwidth=2, arrowhead=none]
                do j=1,n_edges
                    attributes = get_attributes_string(me%vertices(i)%edges(j)%label, &
                                                       me%vertices(i)%edges(j)%attributes)
                    str = str//tab//integer_to_string(i)//' -> '//&
                            integer_to_string(me%vertices(i)%edges(j)%ivertex)//' '//attributes//newline
                end do
            else
                ! Example:   1 -> 2,5,10
                str = str//tab//integer_to_string(i)// merge(' -> ','    ',n_edges/=0)
                do j=1,n_edges
                    ! comma-separated list:
                    str = str//integer_to_string(me%vertices(i)%edges(j)%ivertex)
                    if (n_edges>1 .and. j<n_edges) str = str//','
                end do
                str = str//';'//newline
            end if

        end if
    end do

    str = str//newline//'}'

    contains

        function get_attributes_string(label, attributes) result(str)
            !! create the full attributes string for an edge or node.
            character(len=:),allocatable,intent(in) :: label !! if not allocated or blank, then not used
            character(len=:),allocatable,intent(in) :: attributes !! if not allocated or blank, then not used
            character(len=:),allocatable :: str !! the attributes string, enclosed in brackets

            character(len=:),allocatable :: tmp_label
            logical :: has_label, has_attributes

            has_label = allocated(label)
            if (has_label) has_label = label /= ''
            if (has_label) tmp_label = 'label="'//trim(adjustl(label))//'"'

            has_attributes = allocated(attributes)
            if (has_attributes) has_attributes = attributes /= ''

            if (has_label .and. has_attributes) then
                str = '['//trim(adjustl(attributes))//','//tmp_label//']'
            elseif (has_label .and. .not. has_attributes) then
                str = '['//tmp_label//']'
            elseif (.not. has_label .and. has_attributes) then
                str = '['//trim(adjustl(attributes))//']'
            else ! neither
                str = ''
            end if
        end function get_attributes_string

    end function dag_generate_digraph