0

I need to replace the EdgeList of a graph with a new list of edges generated by other code.

I use an hour glass display for vertices:

vf[{xc_, yc_}, name_, {w_, h_}] := 
  Block[{xmin = xc - w, xmax = xc + w, ymin = yc - h, ymax = yc + h}, 
   Polygon[{{xmin, ymin}, {xmax, ymax}, {xmin, ymax}, {xmax, ymin}}]];

The graph is of the following form:

    graph = Graph[List[1, 2, 3], List[DirectedEdge[1, 3], DirectedEdge[2, 3]], 
 List[Rule[ImageSize, List[240, 240]], 
  Rule[VertexCoordinates, 
   List[List[0.`, -1.`], List[1.`, -1.`], List[1.`, 0.`]]], 
  Rule[VertexLabels, 
   List[Rule[3, 
     Placed[List[Style[3, RGBColor[1, 0, 0]], 
       Style[3, RGBColor[0, 0, 1]]], List[Before, After]]], 
    Rule[1, Placed[
      List[Style[1, RGBColor[1, 0, 0]], Style[2, RGBColor[0, 0, 1]]], 
      List[Before, After]]], 
    Rule[2, Placed[
      List[Style[2, RGBColor[1, 0, 0]], Style[1, RGBColor[0, 0, 1]]], 
      List[Before, After]]]]], Rule[VertexShapeFunction, List[vf]], 
  Rule[VertexWeight, List[1, 2, 3]]]]

Its edges are: {1 -> 3, 2 -> 3}

which I want to replace with: {2 -> 3, 1 -> 2}

(this is only an example, the solution needs to work on any replacing set of edges)

Without affecting any other aspects of the graph. I want to preserve all aspects of the graph as given in its definition, bar the edges. These can be changed. I.e. I want to preserve colours, vertices, weights and labels as specified in the graph.

The following approach:

 EdgeList[graph] = {2 -> 3, 1 -> 2}  

Gives the error: Tag Edgelist in Edgelist[...] is Protected.

How do I change the EdgeList (without altering the other properties of a graph)?

ExpressionCoder
  • 1,678
  • 7
  • 15
  • 1
    "Without affecting any other aspects of the graph." Can you please be specific about what other aspects you want to preserve and why Graph[VertexList[g], newEdges] doesn't work for you? – Szabolcs Sep 27 '22 at 20:39
  • @Szabolcs I tried Graph[VertexList[g], newEdges] first. It produces an odd output. I don't know how to copy outputs into my question. But if you try it on the graph I specified, you should see that the end result is incorrect. – ExpressionCoder Sep 27 '22 at 21:24
  • The expression you posted is incomplete, as vf is missing. Please be specific about what you mean by "the end result is incorrect". You did not respond about what aspects of the original graph you want to preserve. – Szabolcs Sep 27 '22 at 21:28
  • I added the definition of the hour-glass vertices vf. The end result is incorrect in that it does not evaluate. – ExpressionCoder Sep 27 '22 at 21:31
  • Sorry, I want to preserve all aspects of the graph as given in its definition, bar the edges. These can be changed. I.e. I want to preserve colours, vertices, weights and labels as specified in the graph. – ExpressionCoder Sep 27 '22 at 21:35
  • I still don't understand. What do you mean by "The end result is incorrect in that it does not evaluate."? Are you saying when when you evaluate the input Graph[VertexList[graph], newEdges], Mathematica returns it unchanged, without any error messages? Do you mean that you do receive a result, but when you take that result and try to evaluate it a second time, it fails? If so, how does it fail, what errors are there? Can you show a complete minimal example that illustrates the problem? (1) This is what I did (in full detail) (2) This is what I expected (3) This is what I got instead. – Szabolcs Sep 27 '22 at 21:36
  • OK, after the last edit it is clearer. It sounds like you want to preserve vertex properties. Vertex colours and labels are encoded in these. – Szabolcs Sep 27 '22 at 21:38
  • 1
    If what you want to preserve ends up being all about presentation, you might try doing all of your processing work (regenerating the Hasse diagram relations) in the raw, so to speak. Then apply all of your presentation options as a final step. So augmenting @Szabolcs suggestion like this: Graph[VertexList[graph], newEdges, displayOpts] (where you've defined displayOpts to be the whole sequence of options that you want). – lericr Sep 27 '22 at 21:39
  • @Szabolcs Yes, I want to preserve vertex properties. Rather than posting more, I will look into this tomorrow and post a refined question based on it. Meanwhile, is there a way for me to copy output here? I can take snapshots if that is needed but wonder if output can be copied directly (similarly to code). – ExpressionCoder Sep 27 '22 at 21:44
  • Yes, what @lericr said sounds like a good idea, if performance becomes a problem, or if you hit any bugs in Mathematica's property handling. Otherwise, the answer by lericr is the easiest way. Recent versions (post 12.1, as I remember) fixed many such bugs. – Szabolcs Sep 27 '22 at 21:44
  • @lericr Indeed, I want to preserve the presentation. I will consider matters further and refine the question tomorrow. – ExpressionCoder Sep 27 '22 at 21:45
  • @Szabolcs I will try lericr's approach tomorrow. I have the latest version of Mathematica (13.1). – ExpressionCoder Sep 27 '22 at 21:46

2 Answers2

2

The trouble is that a Graphics is considered an atomic object, where a user does not have any access.

However, you may use the utility of Carl Woll, that returns an inactive FullForm of the atomic object. You may then change this and re-activate. The code for this can be found at: How to extract parts from atomic expressions like DelaunayMesh and Graph?

For your example: You want to change the edge 1->3 into 1->2 and leave the edge 2->3 alone. This can be done after you loaded "Nucleus":

Before:

graph

enter image description here

Now we change the edge 1->3 to 1->2:

Nucleus[graph] /. {1, 3} -> {1, 2} // Activate

enter image description here

Daniel Huber
  • 51,463
  • 1
  • 23
  • 57
1

I think this might be what you want:

newEdges = {2 -> 3, 1 -> 2};
EdgeAdd[EdgeDelete[graph, EdgeList[graph]], newEdges]

To be clear, this generates a new Graph object, it does not override the value of graph. If you want that you could do:

newEdges = {2 -> 3, 1 -> 2};
graph = EdgeAdd[EdgeDelete[graph, EdgeList[graph]], newEdges]
lericr
  • 27,668
  • 1
  • 18
  • 64
  • This will preserve vertex and graph properties, at great cost to performance. It will not preserve edge properties, in case OP meant to replace each edge by another one without losing its properties. It is not possible to give a good answer unless the question is clarified. – Szabolcs Sep 27 '22 at 21:03
  • @Szabolic The above solution works. I am concerned indeed about performance. In a nutshell: I extend a Hasse diagram by adding edges and want to create a new Hasse diagram, i..e get rid of transitive closures in the relationships caused by adding some of the new edges. Currently I do this by regenerating the Hasse diagram relations (after adding new edges), then replacing the old edges with the new ones. I could try to just use EdgeAdd, but then would need to weed you the relations that can be obtained by transitive closure. – ExpressionCoder Sep 27 '22 at 21:26
  • To your question about rewriting the post: As long as the spirit of the question is the same, I think it's fine. A better description with better details might lead to better answers. – lericr Sep 27 '22 at 21:31
  • @lericr I accepted the answer. In relation to efficiency, raised by Szabolic: I need to carry out graph manipulations on graphs of size at most 7 nodes. However, I need to generate the graphs for 7!, i.e. 5040 cases. I did not use Mathematica in such a context before. I can aim to do your "raw" approach, but wonder if your solution may simply work for 5040 instances. I will carry out the experiment first using the method suggested in your answer (unless someone flags that it is clear from the start this won't work due to efficiency issues). – ExpressionCoder Sep 28 '22 at 09:22