Best layout for graph with long node labels - layout

My graph has long node labels. Neato makes things overlap; Circo does what I want, it just creates too much space between nodes. I would like to use the Circo result and bring the nodes closer together.
Graph code: https://clbin.com/BbsNP
digraph {
graph [overlap=scale];
graph [bgcolor=white];
node [shape=box];
0 [label="long node label"
,shape=box];
1 [label="long node label"
,shape=box];
2 [label="aoeu aoe uaoeu oae ueaoo"
,shape=box];
3 [label="long node labelau"
,shape=box];
4 [label="aoeu aoe uaoeu oae ueaooeu"
,shape=box];
5 [label="long node labelaoeu"
,shape=box];
6 [label="aoeu aoe uaoeu oae ueaoe"
,shape=box];
7 [label="long node labelaoeuo"
,shape=box];
8 [label="aoeu aoe uaoeu oae ueao"
,shape=box];
9 [label="234 aoeua",shape=box];
10 [label="long node labeluu"
,shape=box];
11 [label="aoeu aoe uaoeu oae ueao"
,shape=box];
12 [label=oeuaoeu,shape=box];
13 [label="long node labelaa"
,shape=box];
14 [label="aoeu aoe uaoeu oae ueao"
,shape=box];
15 [label=aoeu,shape=box];
16 [label=aoeu,shape=box];
0 -> 1 [color=blue];
1 -> 0 [color=blue];
2 -> 1 [color=blue];
3 -> 0 [color=blue];
4 -> 3 [color=blue];
5 -> 0 [color=blue];
6 -> 5 [color=blue];
7 -> 0 [color=blue];
8 -> 7 [color=blue];
9 -> 7 [color=blue];
10 -> 0 [color=blue];
11 -> 10 [color=blue];
12 -> 10 [color=blue];
13 -> 0 [color=blue];
14 -> 13 [color=blue];
15 -> 13 [color=blue];
16 -> 13 [color=blue];
}
Image: http://postimage.org/image/mrcak2021/
circo -T jpg Test.Layout.LongNodeLabel.dot > Test.Layou.LongNodeLabel.jpg

The problem is similar to the one in this recent question. If you're willing to use twopi rather than circo, you can set ranksep to pull in or push out the nodes -- to change "the radial separation of concentric circles," as the documentation describes it.
I changed your graph code to begin like so:
digraph {
graph [bgcolor=white, overlap=true, ranksep=2.75];
Then graphed it using twopi: twopi test_graph.txt -Tpng -otest_graph.png. This produces the following graph:
Here is the original for comparison:

Related

Print values and it's associated index when working with vectors / matrix in J

If I want to check how many values in a vector or matrix are less than a given value
I can use +/ (a < 20). But what if I wanted to know both the specific value and it's index.
Something like (2(value) 5(index)) as a table. I looked at i., i: (which give first and last position) and I. Does sorting first help?
A very common pattern in J is the creation of a mask from a filter and applying an action on and/or using the masked data in a hook or fork:
((actions) (filter)) (data)
For example:
NB. Random array
a =: ? 20 $ 10
6 3 9 0 3 3 0 6 2 9 2 4 6 8 7 4 6 1 7 1
NB. Filter and mask
f =: 5 < ]
m =: f a
1 0 1 0 0 0 0 1 0 1 0 0 1 1 1 0 1 0 1 0
NB. Values of a on m
m # a
6 9 6 9 6 8 7 6 7
NB. Indices of a on m
I. m
0 2 7 9 12 13 14 16 18
NB. Joint results
(I.m) ,: (m # a)
0 2 7 9 12 13 14 16 18
6 9 6 9 6 8 7 6 7
In other words, in this case you have m&# and f acting on a and I. acting on m. Notice that the final result can be derived from an action on m alone by commuting the arguments of copy #~:
(I. ,: (a #~ ]) m
0 2 7 9 12 13 14 16 18
6 9 6 9 6 8 7 6 7
and a can be pulled out from the action on m like so:
a ( (]I.) ,: (#~ ])) m
But since m itself is derived from an action (f) on a, we can write:
a ( (]I.) ,: (#~ ])) (f a)
which is a simple monadic hook y v (f y) → (v f) y.
Therefore:
action =: (]I.) ,: (#~ ])
filter =: 5 < ]
data =: a
(action filter) data
0 2 7 9 12 13 14 16 18
6 9 6 9 6 8 7 6 7

Use # (Copy) as selection or filter on 2-d array

The J primitive Copy (#) can be used as a filter function, such as
k =: i.8
(k>3) # k
4 5 6 7
That's essentially
0 0 0 0 1 1 1 1 # i.8
The question is if the right-hand side of # is 2-d or higher rank shaped array, how to make a selection using #, if possible. For example:
k =: 2 4 $ i.8
(k > 3) # k
I got length error
What is the right way to make such a selection?
You can use the appropriate verb rank to get something like a 2d-selection:
(2 | k) #"1 1 k
1 3
5 7
but the requested axes have to be filled with 0s (or !.) to keep the correct shape:
(k > 3) #("1 1) k
0 0 0 0
4 5 6 7
(k > 2) #("1 1) k
3 0 0 0
4 5 6 7
You have to better define select for dimensions > 1 because now you have a structure. How do you discard values? Do you keep empty "cells"? Do you replace with 0s? Is structure important for the result?
If, for example, you only need the "values where" then just ravel , the array:
(,k > 2) # ,k
3 4 5 6 7
If you need to "replace where", then you can use amend }:
u =: 5 :'I. , 5 > y' NB. indices where 5 > y
0 u } k
0 0 0 0
0 5 6 7
z =: 3 2 4 $ i.25
u =: 4 :'I. , (5 > y) +. (0 = 3|y)' NB. indices where 5>y or 3 divides y
_999 u } z
_999 _999 _999 _999
_999 5 _999 7
8 _999 10 11
_999 13 14 _999
16 17 _999 19
20 _999 22 23

Avoiding a repeated verb name in a train

Consider a dyadic verb g, defined in terms of a dyadic verb f:
g=. [ f&.|: f
Is it possible to rewrite g so that the f term appears only once, but the behavior is unchanged?
UPDATE: Local Context
This question came up as part of my solution to this problem, which "expanding" a matrix in both directions like so:
Original Matrix
1 2 3
4 5 6
7 8 9
Expanded Matrix
1 1 1 1 2 3 3 3 3
1 1 1 1 2 3 3 3 3
1 1 1 1 2 3 3 3 3
1 1 1 1 2 3 3 3 3
4 4 4 4 5 6 6 6 6
7 7 7 7 8 9 9 9 9
7 7 7 7 8 9 9 9 9
7 7 7 7 8 9 9 9 9
7 7 7 7 8 9 9 9 9
My solution was to expand the matrix rows first using:
f=. ([ # ,:#{.#]) , ] , [ # ,:#{:#]
And then to apply that same solution under the transpose to expand the columns of the already row-expanded matrix:
3 ([ f&.|: f) m
And I noticed that it wasn't possible to write my solution with making the temporary verb f, or repeating its definition inline...
Try it online!
Knowing the context helps. You can also approach this using (|:#f)^:(+: x) y. A tacit (and golfed) solution would be 0&(|:{.,],{:)~+:.
(>: i. 3 3) (0&(|:{.,],{:)~+:) 2
1 1 1 2 3 3 3
1 1 1 2 3 3 3
1 1 1 2 3 3 3
4 4 4 5 6 6 6
7 7 7 8 9 9 9
7 7 7 8 9 9 9
7 7 7 8 9 9 9
I don't think it is possible. The right tine is going to be the result of x f y and the left tine is x The middle tine will transpose and apply f to the arguments and then transpose the result back. If you take the right f out then there is not a way to have x f y and if the middle f is removed then you do not have f applied to the transpose.
My guess is that you are looking for a primitive that will accomplish the same result with only one mention of f, but I don't know of one.
Knowing the J community someone will prove me wrong!

Understanding J From

In J:
a =: 2 3 $ 1 2 3 4 5 6
Gives:
1 2 3
4 5 6
Which is a 2 3 shaped array.
If I do:
0 1 { a
I (noting that 0 1 is a 2 shaped list) expected to have back:
1 2 3 4 5 6
But got the following instead:
1 2 3
4 5 6
Reading the documentation I was expecting the shape of the index to kinda govern the shape of the answer.
Can someone clarify what I am missing here?
Higher-dimensional arrays may help make this clear. An array with n dimensions has items with n-1 dimensions. When you select an item from ({) a three-dimensional array, your result is a two-dimensional array:
1 { i. 5 3 4
12 13 14 15
16 17 18 19
20 21 22 23
When you select multiple items from an array, the items are assembled into a new array, using each atom of x to select a item of y. This might be where you picked up the idea that the shape of x affects the shape of the result.
2 1 0 2 { 'set'
test
$ 2 1 0 2
4
$ 'test'
4
The dimensions of the result is equal to the dimensions of x plus the dimensions of the items of y. So, if you have a two-dimensional x taking two-dimensional items from a three-dimensional y, you will have a four-dimensional result:
(2 2 $ 1 1 0 1) { i. 5 3 4
12 13 14 15
16 17 18 19
20 21 22 23
12 13 14 15
16 17 18 19
20 21 22 23
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
16 17 18 19
20 21 22 23
$ (2 2 $ 1 1 0 1) { i. 5 3 4
2 2 3 4
One final note: the monadic Ravel (,) will reduce the result to a list (one-dimensional array).
, 0 1 { 2 3 $ 1 2 3 4 5 6
1 2 3 4 5 6
, i. 2 2 2 2
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
From ({) selects the items of a noun. For 2 3 $ 1 2 3 4 5 6 the items are the two rows because items are the components that make up the noun.
[ a=. 2 3 $ 1 2 3 4 5
1 2 3
4 5 1
0 { a
1 2 3
If you just had 1 2 3 then the items would be the individual atoms.
[ b=. 1 2 3
1 2 3
0 { b
1
If you used 1 3 $ 1 2 3 then there is only one item and the result would be
[ c=. 1 3 $ 1 2 3
1 2 3
0 { c
1 2 3
The number of items can be found with Tally (#), and is the lead dimension of the Shape ($) of the noun.
$ a
2 3
$ b
3
$ c
1 3
# a
2
# b
3
# c
1

What do .txt files have to look like so that data can be read out of it?

I created a .txt file that looks like this
4 4 4 !DIM_M, DIM_L, DIM_N
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
2 20 !DIM_START, DIM_END
But the point is that if I add now some comments like the Name of the Matrices that I use, then I get some errors, i.e.
4 4 4 !DIM_M, DIM_L, DIM_N
1 2 3 4 !A
5 6 7 8
9 10 11 12
13 14 15 16
1 2 3 4 !B
5 6 7 8
9 10 11 12
13 14 15 16
2 20 !DIM_START, DIM_END
it doesn't work any more. The Fortran file that I use to read the .txt file is
! OPEN FILE
OPEN(UNIT=39, STATUS='OLD', ACTION='READ',FILE='input.txt',IOSTAT=IERROR)
!READ DIMENSIONS + CHECK IF SUCCESFUL
READ(39,*,IOSTAT=IERROR)DIM_M, DIM_L, DIM_N
ALLOCATE(A(DIM_M,DIM_L),B(DIM_L,DIM_N), C(DIM_M,DIM_N), STAT=IERROR)
READ (39,*, IOSTAT=IERROR)A
READ (39,*, IOSTAT=IERROR)B
READ (39,*) DIM_START, DIM_END
CLOSE(UNIT=39)
I left out all the parts where I check if reading the file worked (using IOSTAT). Any ideas how I could Change this?
Read it in as a string, then only use the part of the string up to the "!" for reading the variables.
Since you provided a non-compiling example, I will respond in kind.
! OPEN FILE
CHARACTER(LEN=132) :: ALine
CHARACTER(LEN=1), PARAMETER :: Bang '!'
OPEN(UNIT=39, STATUS='OLD', ACTION='READ',FILE='input.txt',IOSTAT=IERROR)
!READ DIMENSIONS + CHECK IF SUCCESsFUL
READ(39,*,IOSTAT=IERROR) ALine
IF(INDEX(ALine,bang) > 0) THEN
READ(ALine(1:INDEX(ALine,'!')-1) ,*,IOSTAT=IERROR) DIM_M, DIM_L, DIM_N
ELSE
READ(ALine ,*,IOSTAT=IERROR) DIM_M, DIM_L, DIM_N
ENDIF
ALLOCATE(A(DIM_M,DIM_L),B(DIM_L,DIM_N), C(DIM_M,DIM_N), STAT=IERROR)
!Etc
If there are always DIM_M respectively DIM_L numbers on one line read them just in a loop
do l = 1, dim_l
read(39,*,iostat=ierror) A(:,l)
if (ierror /= 0) do something
end do
do n = 1, dim_n
read(39,*,iostat=ierror) A(:,n)
if (ierror /= 0) do something
end do

Resources