Requirements: Update SharpPlot to v3.37 from my.dyalog.com > Downloads > Tools & Interfaces > GUI Tools > SharpPlot
SharpPlot v3.37 introduces Network Maps as a new chart type, and we’re going to use it to display the output of the ]XRef
user command, which displays cross-references between all kinds of APL names :
]XRef ⎕SE.Parser
DDEEEFLLMMNNPPPPPPPPPPPQQSSSTUaaaabbbcdddddddfffiilmmmmmmnnnnnnppppqqqqrrrsssssssssstttttuvvvxx∆⍵⍺
EeRnrOOSAOAsRrsssssssss.uwwwrPrrrr:alu.aaaeee.ei.fq.aeioo.adeop.Daa.1mq.et:eipqtwwww:aqwxp.an.C...
LlRd:RW.XDRwEo:.eeeeeee.oDTiaPgggg:d.t.tttQff.ax.:..smndd..awv..art..:..qb:t.lzr.imp:b.vtp.lc.u...
I.OT:CE.APGiFp:Pttttttt.t.atpE.psv:....aaau.i.tC.:..k.lei..:....tm...:....:..i.:.tao:l...e....t...
M.Rr:ER.ROStIa:a........e.bc.R.o.a:....:..o.n.ua.:....elf..:....as...:....:..t.:..ts:e...r....:...
I.0a:S..GS.cXg:r.Samnpu.s.lh.:.s.l:....:ASt.e.rs.:....n.i..:....:....:....:..P.:....:....C....:...
T..p:P..S:.h.a:s.wloarp.:.e..:...u:....:rwe.d.ee.:....:.e..:....:....:....:..a.:....:....a....:...
E...:A...:.e.t:e.ildrep.:....:...e:....:gD..:.s..:....:.r..:....:....:....:..r.:....:....s....:...
R...:C...:.s.e:..toigfe.:....:...s:....:u...:....:....:.s..:....:....:....:..m.:....:....e....:...
....:E...:....:..cwfsir.:....:....:....:m...:....:....:....:....:....:....:..s.:....:....:....:...
....:....:....:..hni.x..:....:....:....:e...:....:....:....:....:....:....:....:....:....:....:...
....:....:....:...oe....:....:....:....:n...:....:....:....:....:....:....:....:....:....:....:...
....:....:....:...sr....:....:....:....:t...:....:....:....:....:....:....:....:....:....:....:...
....:....:....:...ps....:....:....:....:s...:....:....:....:....:....:....:....:....:....:....:...
....:....:....:...a:....:....:....:....:....:....:....:....:....:....:....:....:....:....:....:...
....:....:....:...c:....:....:....:....:....:....:....:....:....:....:....:....:....:....:....:...
....:....:....:...e:....:....:....:....:....:....:....:....:....:....:....:....:....:....:....:...
[FNS] - - - - : - - - - : - - - - : - - - - : - - - - : - - - - : - - - - : - - - - : - - - - : - - - -
Parse G.GG○G G GGGG. . . : . ○F.G.G:○○○○○! . ○GGF.○. .○F ○ .○. . ○!○○○G○○! : .○○○○ F :○○○○○○ ○ : ○○.F! .
Propagate ○ . . . : . . . . : . . G . : . .○. . : . . . . : . . .○. : . . . . : . . .○. ○○. . . . :○. . . .
Quotes . . . . : . . . . : . ○ . . : . . . . : . . . .○: .○. . ○ : . . . . ○ . . . . ○ . . .○. : . . . .
Switch . G . . : . . . . : . . G .G: . . . . : . ○ . . : . . . . : . . . . : ○ .○. . : . . . . :○. . . .
deQuote . . . . : . . . . : . . . . : . . . . : . . . . :○○ . . . : . . . . : . . . . ○ . . . . : . . . .
fixCase . . . . : . . . . : . . . . : . . . . : . . . . : . . . . : . . . . : . . . . : . . . . : . . .○.
if . . . . : . . . . : . . . . : . . . . : . . . . : . . . . : . . . . : . . . . : . . . . : . . . .
init G.G. G GGGGGGFGGGGGGGGG.F.GF :○. .○. ○ : . . ○○F F . ○ ○ ○○: . .G. . : . . . .F: . . . . F . GF. .
splitParms . . . . : . . . . : . ○ . . : . . .○.○: . . . . : . . . ○ : .○○ ○ ○○:○. .○. . : . .○. .○: . . . .
sqz . . . . : . . . . : . . . . : . .○. . : . . . . : . . . . : . . . . : . .○. . : . . . . : . . .○.
upperCase . . .G. : . . . . : . . . . G . .○. . : . . . .○: . . . . : . . . . : . .○. . : . . . . : . . .○.
xCut . . . . : . . . . : . . . . : . . . . : . . . . : . . . . : . . . . : . . . . : . . . . : . . .○○
We can capture the output of the user command by doing either
]mat←XRef ⎕SE.Parser
(from session)
or
mat←⎕SE.UCMD']XRef ⎕SE.Parser'
(from code)
Until Dyalog v16.0 (which has ]XRef -raw
), we need to parse the output of ]XRef
to get a square link matrix, along with the full list of nodes (in row/column order of the matrix) and list of original rows (functions).
∇ (mat nodes rows)←GetMatrix mat;nodelabs;rows;cols;labs;cat;diag
(rows mat)←2↑(1,2</∧⌿mat=' ')⊂[2]mat ⍝ cut at empty column
(cols mat)←2↑(1,2<⌿∧/mat∊' -:')⊂[1]mat ⍝ cut at - - - - : - - - -
mat←1↓[1](' '∨.≠mat)/mat ⍝ trim first row and empty columns
rows←~∘' '¨↓(-1⊃⍴mat)↑[1]rows ⍝ row titles (list of strings)
cols←~∘' .:'¨↓(-2⊃⍴mat)↑[1]⍉cols ⍝ col titles (list of strings)
nodes←rows∪cols ⍝ all titles
mat←((mat,' ')⍪' ')[rows⍳nodes;cols⍳nodes] ⍝ square matrix of nodes
∇
Now let’s wrap the SharpPlot initialisation into a single function that uses the .NET version if available and falls back to the cross-platform APL workspace if not:
∇ {dotnet}←Init
:If dotnet←(,'W')≡3⊃'.'⎕WG'APLVersion'
⍝ .Net assembly (windows only)
⎕USING←',sharpplot.dll' ',system.drawing.dll'
:Else
⍝ APL workspace (all platforms)
:If 0=⎕NC'Causeway' ⍝ copy workspace only once
(System.Drawing←System←⍎'Causeway'⎕NS'').(⎕CY'sharpplot.dws')
:EndIf
:EndIf
∇
Then we can write a platform-independent function that returns the SharpPlot instance with the chart drawn on it. We split nodes into two categories, functions and globals (ignoring locals and labels) and split links by destination node. By default, DrawNetworkMap lays out node categories on co-centric circles. Also, because the graph is uni-directional, we can afford to use straight links without damaging readability:
∇ sp←name Plot(mat nodes rows);catlabs;nodecat
sp←⎕NEW Causeway.SharpPlot
catlabs←'Function' 'Global' ⍝ links are split by destination node
nodecat←(≢nodes)⍴0 ⍝ ignored by default
((∨⌿mat∊'FR*')/nodecat)←1 ⍝ functions
((∨⌿mat∊'G')/nodecat)←2 ⍝ globals
((nodes∊rows)/nodecat)←1 ⍝ caller functions
sp.Heading←name
sp.HeadingStyle←Causeway.HeadingStyles.Left
sp.SetMargins 40 30 30 30
sp.KeyStyle←Causeway.KeyStyles.(BottomAlign+RightAlign)
sp.SetILabels⊂nodes
sp.SetILabelFont'Arial' 6 System.Drawing.FontStyle.Bold System.Drawing.Color.Black
sp.SetColors⊂System.Drawing.Color.(SkyBlue LightCoral)
sp.SetMarkers Causeway.Marker.Ball
sp.SetMarkerScales 2
sp.SetLineStyles Causeway.LineStyle.Solid
sp.SetPenWidths 0.5
sp.NetworkMapStyle←Causeway.NetworkMapStyles.(SplitByDestination+Dissected+ArrowLines+FixedArcs+NoAxes+NoLinkKey)
sp.SetNetworkMapLinkArc 0 ⍝ straight lines
sp.SetArrowStyle 5 ⍝ fixed-size arrows
sp.SplitBy nodecat catlabs
sp.DrawNetworkMap⊂↓(mat∊'GFR*') ⍝ use a single width for all valid links
∇
We can then save the graph as SVG to a file (here we use the SvgMode that scales the SVG to fit its container):
sp.SaveSvg 'XRef.svg' Causeway.SvgMode.FixedAspect
Or, if feeding a web server or renderer, we can grab the SVG as a single string without writing to disk:
svg←sp.RenderSvg Causeway.SvgMode.FixedAspect
Windows users will be able to use the SharpPlot Viewer:
vw←⎕NEW Causeway.SharpPlotViewer sp
vw.Show ⍬
More examples of Network Maps can be found on the SharpPlot.com website in the Network Map Tutorials. To translate C# examples into APL, you can refer to the SharpPlot Rosetta Stone.