Sankey diagrams

Started by Yacine, August 23, 2023, 06:03:43 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Yacine

Yes, Visio has become boring in the year 2023. How pity.
So, let's revive an old project, to bring some life in da house.

There were those Sankey diagrams that so many talked about.
Me too. I made several attempts to set up something nice, but I needed a real deadline in a real-world project to get me to finish the project.
Initially I wanted to commercialize the solution and even asked Paul whether he would host it alongside his tools. Lazy as you know me, I never found the motivation to make it sellable. And why anyway? There are several products out there doing a very good job, who am I to compete against them. But I'm also a fervent defender of the open source thought. So, I am presenting you the semi-finished solution.
Sorry for the long intro.

First some key ideas that helped me.
1)   Shapesheets magic alone won't suffice to do the job. VBA Makros were necessary.
2)   Despite you see only flow arrows in Sankey diagrams, there is a second important entity to build them up, nodes. It is where the flows end or start from. They do the position work to space the arrows properly and calculate their flow amounts.

Features

The flow arrow shapes
They are groups containing a connector for defining the path of the arrow. The connector is glued to a beginning and an ending shape. When the arrow is to be drawn, a macro will insert the proper shape begin and end from a stencil, do an outline of the connector with the proper distance, join these 4 new shapes, and fill them.

Node shapes
The node shapes are simple rectangles with connection points, depending on the flow direction and the connected points, it will re-arrange the positions of the connected points.

Coloring of the flow shapes
The flow shapes can be colored by defining their fill color, easy.
But there is another option to colorize them automatically based on custom properties for their begin and end values and a scale defined at page level that maps a min and max value to 2 colors. The macro then fills the arrow with a gradient matching the begin and end value of this arrow. This second option can be used to show temperatures of flows for example, or any other similar information.

Skeleton
The way the flow connectors route is defined by the orientation of the begin and end sub-shapes. They can be oriented by means of prop fields, in which you set the angle.
The connector sub-shape itself can also be accessed, but as you don't want it to be visible in your final document, it sits on a hidden layer. To make it visible, the page has an action row to switch the visibility of this layer ("Show flow skeleton").

Trigger
The drawing process takes several seconds. That is why it is triggered manually – at shape level with an action row and on page level for all the flow shapes.

Continuous versus intermittent flows
In the business I work in, I have continuous flows as well as intermittent ones and I wanted to show this aspect in the diagrams. When setting a flow to intermittent, two arrows are drawn – a narrow one for the average value and a wider one showing the instant flow.
Yacine

Yacine

And here a first Video on Youtube.
https://youtu.be/c1jIz1Daw6g

Too short, no speech, sorry.
Yacine

Yacine

And since this is about entertaining you guys, here is a quiz.

Visio crashes when the flow master is dropped from the stencil on the drawing.
Dropping the shapes triggers the re-draw. This opens the draw window of the group, does stuff and when the code closes the window Visio just disappears.
This does not happen when duplicating the flow shape, only when dropped from the stencil.

I tried:
- doevents and for loops
- instead of just closing the window, I got the handle of the previous window, the new one, then switched to the main one before closing the group window.
- ... stuck, no idea.

I wonder if someone can give me a hint.
Yacine

Yacine

Every Visio search ends at Visguy.com forum?
Yacine

wapperdude

@Yacine:  So far I can confirm that Visio crashes as you indicate.
Visio 2019 Pro

wapperdude

Interesting.  It seems like there are 2 different files. 
One is Sankey_2023_08_20_2.vsdm:flow.75 <GROUP> and the other is just file name without the trailing flow75 text.  that was kinda weird.  The first one is difficult to work with.  The normally named file was better behaved.  But dropping the flow shape on existing page caused Visio to crash.  Same file, with a new page then there is no crash.

That's as far as I've gotten.


















Visio 2019 Pro

Yacine

Yes, as I said the macro opens the drawing window of the group to perform the redraw operations.
This window is then named file name + shape (group) name.


The crash happens when after the drop from the stencil, the shape is redrawn. The routine in cause is in the module ModFlow and the sub drawFlow.
If you put a break point right before "drawWin.close", you'll see that everything performs well. It is exactly the close command of the window that causes the crash.



Sub drawFlow(shp As Shape)
    Dim subShp As Shape
    Dim flowShp As Shape
    Dim sourceShp As Shape
    Dim targetShp As Shape
    Dim sourceShp2 As Shape
    Dim targetShp2 As Shape
   
    Dim i As Integer
    For i = shp.Shapes.Count To 1 Step -1
        Set subShp = shp.Shapes(i)
        Select Case subShp.Name
        Case "flow"
            Set flowShp = subShp
        Case "source"
            Set sourceShp = subShp
        Case "source2"
            Set sourceShp2 = subShp
        Case "target"
            Set targetShp = subShp
        Case "target2"
            Set targetShp2 = subShp
        Case Else
            subShp.Delete
        End Select
    Next i
   
   
    Dim mainWin As Window
    Dim drawWin As Window
    Set mainWin = ActiveWindow
    Set drawWin = shp.OpenDrawWindow
    drawWin.Activate

   
    Dim repr_type As String
    Dim repr_2 As String
    '******** Define a representation type as variable to use later in a SELECT statement ***********
    If shp.Cells("prop.FlowType").ResultStr("") = "Continuous" Then
        repr_type = "cont_" ' cont_
    Else
        repr_type = "interm_"
        If shp.Cells("prop.OutputType").ResultStr("") = "Continuous" Then
            repr_type = repr_type & "cont_" ' interm_cont_
        Else
            repr_type = repr_type & "interm_" ' interm_interm_
        End If
    End If
   
    If shp.Cells("prop.Colouring").ResultStr("") = "Gradient" Then
        repr_type = repr_type & "grad"
        repr_2 = "grad"
    Else
        repr_type = repr_type & "plain"
        repr_2 = "plain"
    End If
        ' ALL CASES:
        ' cont_grad - regular arrow with gradient over second property
        ' cont_plain - regular arrow with one plain color
        ' interm_cont_grad  - it's the smaller arrow (hourly rate) that gets the gradient. The bigger arrow is painted with the background colour
        ' interm_cont_plain - same as above but plain
        ' interm_interm_grad - focus is on the instantanuous flow. Its the bigger arrow that gets the gradient, the smaller gets the background
        ' interm_interm_plain - same as above, but plain
       
   
    '***************************************************
    Dim arrowShp As Shape
    Dim arrowShp2 As Shape
   
    Select Case repr_type
    Case "cont_grad", "cont_plain"
        Set arrowShp = drawArrow(shp, flowShp, sourceShp, targetShp, shp.Cells("user.HourlyScaledFlow").ResultIU / 2)
        colorArrow shp, arrowShp, repr_2
    Case "interm_cont_grad"
        Set arrowShp = drawArrow(shp, flowShp, sourceShp, targetShp, shp.Cells("user.HourlyScaledFlow").ResultIU / 2)
        colorArrow shp, arrowShp, repr_2
        Set arrowShp2 = drawArrow(shp, flowShp, sourceShp2, targetShp2, shp.Cells("user.InstantScaledFlow").ResultIU / 2)
        colorArrow shp, arrowShp2, "plain"
        arrowShp.BringToFront
    Case "interm_cont_plain"
        Set arrowShp = drawArrow(shp, flowShp, sourceShp, targetShp, shp.Cells("user.HourlyScaledFlow").ResultIU / 2)
        colorArrow shp, arrowShp, "plain2"
        Set arrowShp2 = drawArrow(shp, flowShp, sourceShp2, targetShp2, shp.Cells("user.InstantScaledFlow").ResultIU / 2)
        colorArrow shp, arrowShp2, "plain"
        arrowShp.BringToFront
    Case "interm_interm_grad"
        Set arrowShp = drawArrow(shp, flowShp, sourceShp, targetShp, shp.Cells("user.HourlyScaledFlow").ResultIU / 2)
        colorArrow shp, arrowShp, "plain"
        Set arrowShp2 = drawArrow(shp, flowShp, sourceShp2, targetShp2, shp.Cells("user.InstantScaledFlow").ResultIU / 2)
        colorArrow shp, arrowShp2, repr_2
        arrowShp.BringToFront
    Case "interm_interm_plain"
        Set arrowShp = drawArrow(shp, flowShp, sourceShp, targetShp, shp.Cells("user.HourlyScaledFlow").ResultIU / 2)
        colorArrow shp, arrowShp, "plain"
        Set arrowShp2 = drawArrow(shp, flowShp, sourceShp2, targetShp2, shp.Cells("user.InstantScaledFlow").ResultIU / 2)
        colorArrow shp, arrowShp2, "plain2"
        arrowShp.BringToFront
    End Select
    flowShp.BringToFront
    mainWin.Activate
'    ActiveDocument.Save
    DoEvents
    drawWin.Close
    DoEvents
End Sub


Poor mans solution:
Remove the automatic trigger to redraw the shape.
In the user cell "trigger", I made the shape redraw itself when the scale at page level changes. That works well when the shape is already on the page, so I don't suspect that the function itself does the crash.

Yacine

wapperdude

I hadn't gotten so far as to investigate the code.

How is the new file name used.  I don't recognize the syntax at all.  When that file opens, it shows only page 3.  Can't see any other pages.  When I switch to original file, I see all pages, 1st one being test.  If I create new, blank page and drop flow shape, code executes much quicker, and Visio does not crash.

So, from limited hands-on experience, it seems the presence of other shapes is a factor.
Visio 2019 Pro

Yacine

It is not a new file, but it is the same as when you select a group, then right mouse click "open group". A new window opens and only the group content is shown.
Close it and you're back in your original drawing.

And yes, it seems to have something to do with shapes being on the drawing and specially with the stencil itself.
Yacine