I have code that generates a Matrix Mat
(Mat =
data) that, when the graph is plotted, AdjacencyGraph[Mat]
gives a graph.
Now, there are many inbuilt functions for GraphLayout
. Once we fix a particular GraphLayout
. For a particular GraphLayout
, we get the vertex coordinates when we use GraphEmbedding
.
Let us take a simple example if I have a matrix for a square geometry (square lattice). Then its graph will have a square face. Following the previous paragraph strategy, I will get the coordinates for the vertices like {{0,0}, {0,1},...{0,Lx},...{Ly,Lx}}
, where Lx
and Ly
is the number of vertices along x
and y
. That is related to the size of the matrix, which is (Lx X Ly) X (Lx X Ly)
. One can do this for honeycomb or triangle lattices.
However, my graph has higher connectivity that doesn't fall in the above case (meaning it's not Euclidean). Suppose I use the existing GraphLayout
. Then the coordinates are not as per the hyperbolic plane. For instance, if I use the GraphLayout -> "SpringElectricalEmbedding"
then it uses the particular mechanism (minimizing the spring energy, not important here) to have a graph layout. But it starts to be a problem if I plot different (hyperbolic) graphs, where it is fully messed up and doesn't look good. So I can't extract coordinates rightly.
As an input, I will give the matrix with particular connectivity between the vertices. For example, below, I give as an input a lattice {8,3}
in the matrix form, which is a polygon with 8 sides, and at each vertex, three such polygons (octagon) meet. As an output, I want the coordinates for all the vertices so that the coordinates satisfy a hyperbolic distance formula distance[z1,z2]
. In other words, it is a fixed distance with a hyperbolic metric. So is there a way to create a custom GraphLayout
that does it?
On idea from my side. Maybe we can create an EdgeWeight
that encodes the distance function that, in turn, dictates how two edges should be connected? (no idea how good it is, maybe not at all)
MWE:
Mat = data;
graphMat = GraphEmbedding[AdjacencyGraph[ConnectMat, VertexCoordinates -> Coords, VertexLabels -> None, ImageSize -> Large, GraphLayout -> "SpringElectricalEmbedding"]
distance[z1_, z2_] := 1./2 ArcCosh[1 + (2 Abs[z1 - z2]^2)/((1 - Abs[z1]^2) (1 - Abs[z2]^2))];
Update: Can we use the EdgeWeight
function, perhaps? Where this EdgeWeight
account for the hyperbolic distance?
One example from Euclidean (not exactly what want though using ChatGPT)
g = GridGraph[{10, 10}, VertexLabels -> "Name",
EdgeWeight -> Range[1, 4 - 1/60, 1./60],
EdgeLabels -> "EdgeWeight"];
distance[v1_, v2_] := Norm[v1 - v2];
calculateLayout[g_, distance_] :=
Module[{vertices, edges, layout}, vertices = VertexList[g];
edges = EdgeList[g];
layout =
AssociationThread[vertices,
Flatten[Outer[List, Range[10], Range[10]], 1]];
Do[With[{v1 = First[edge], v2 = Last[edge]},
While[distance[layout[v1], layout[v2]] >
PropertyValue[{g, edge}, EdgeWeight],
layout[v2] += 0.01*(layout[v1] - layout[v2])]], {edge, edges}];
layout];
layout = calculateLayout[g, distance];
ambush =
Graph[g,(*VertexCoordinates->layout,*)VertexLabels -> "Name"(*,
EdgeLabels->"EdgeWeight"*)]
GraphEmbedding[ambush]
I would have rather wanted to have the coordinates look like the values on the Edge
instead of the original coordinates.
EdgeWeight
, you have to enable it manually. Second, I don't think you can modify the"SpringEmbedding"
in any way to account for your metric because you cannot redefine the energy function, and usingEdgeWeight
s will not help because your metric is not translationally invariant. Third, you can try writing your own embedding algorithm – it is in principle just a very simple minimizator (likeFindMinimum
) with a scoring function being ... $\endgroup$