Creating Edges

May 14, 2011 at 4:31 PM

Hey,

I started to create my own graph from a database. First I extracted the stuff to a list and now, i want to create the Verticles and Edges.

For that I wrote the code:

 IVertexCollection oVertices = nodeXLControl1.Graph.Vertices;
             IEdgeCollection oEdges = nodeXLControl1.Graph.Edges;

             int i = 0;
          
            foreach (string s in structure)
            {

                
                IVertex OVertex = oVertices.Add();
                OVertex.SetValue(ReservedMetadataKeys.PerVertexShape, VertexShape.Label);
                OVertex.SetValue(ReservedMetadataKeys.PerVertexLabel, s);
                OVertex.SetValue(ReservedMetadataKeys.PerVertexLabelFontSize, 30F);
                
                OVertex.Name = "OVertex" + i;

                i++;
            }
            
            
            int j = 1;
           
            foreach (IVertex v in oVertices)
            {
                Console.Write(v.ID);
                
               
                IEdge oEdge = oEdges.Add(v., , false);
               
                j++;
            }
           

The creation of Verticles works fine. But I don't know how to handle the creation of Edges.

In each loop I want wo create a Edge from Vertex1 to Vertex2, Vertex 2 to Vertex3 and so one.

Could someone please help me?

 

Thanks

Peter

May 14, 2011 at 7:08 PM
Edited May 16, 2011 at 5:21 PM

Peter:

Because you've named your vertices in a predictable pattern, you could use the IVertexCollection.Find() method to retrieve the vertices you need to pass to the IEdgeCollection.Add() method.  Find() takes a vertex name and gives you the vertex if it was found.  Your edge-adding code would then look something like the following.  (I haven't compiled this, so I can't guarantee that I haven't made any typos here.)

Int32 iVertices = oVertices.Count;

for (Int32 j = 0; j < iVertices - 1; j++)
{
    IVertex oVertex1, oVertex2;
    Boolean bVertexFound;

    bVertexFound = oVertices.Find("OVertex" + (j + 0), out oVertex1);
    Debug.Assert(bVertexFound);

    bVertexFound = oVertices.Find("OVertex" + (j + 1), out oVertex2);
    Debug.Assert(bVertexFound);

    IEdge oEdge = oEdges.Add(oVertex1, oVertex2, false);
}

That will work fine if you have a small number of vertices whose names follow a predictable pattern.  But if you have many vertices (hundreds, say), the code will be slow because the Find() method does a linear search each time you call it.  In that case, you could add your vertices to a System.Collections.Generic.Dictionary<KeyType, IVertex> at the same time you're adding them to the Vertices collection, then quickly retrieve them from the Dictionary when you're adding your edges.  The Dictionary key could be the vertex Name, vertex ID, or whatever makes sense in your particular application.  The Dictionary will probably be temporary -- you can discard it when you're done populating the graph.

-- Tony

May 16, 2011 at 8:26 AM

Hey Tony,

thanks for the great input. It works fine! :)

I have to additional questions:

1. I want to redraw my graph with other parameters. So I have to reset the elementHost, unset my Vertices and Egdes and then call the function again, right? How do I do that?

2. I want to use the Sugiyama Layout. But I get this error message: "Microsoft.NodeXL.Visualization.Wpf.NodeXLControl.AsyncLayout: An asynchronous layout is in progress.  Check the IsLayingOutGraph property before calling this."
What is my mistake?

(The Graph has 3 Vertices and 2 Edges....)

Thanks again!

Peter

May 16, 2011 at 5:20 PM
Edited May 16, 2011 at 5:23 PM

Peter:

1. By "redraw my graph with other parameters," do you mean that you want to repopulate the graph with a new set of vertices and edges?  If so, call NodeXLControl.ClearGraph(), populate the graph again, and call DrawGraph() again.  You don't need to rerun any of the code involved in creating and connecting your ElementHost.  The ElementHost stuff needs to be done just once.

2. Are you setting the NodeXLControl.Layout property after calling DrawGraph()?  You should set it before calling DrawGraph().  When you call DrawGraph(), the NodeXLControl's Layout object starts to lay out the graph in preparation for drawing it, and the Layout object can't be replaced while it's busy doing that.  That's why you're getting the error message.

-- Tony

May 16, 2011 at 7:45 PM

Hey Tony,

thanks point 1 works fine.

What I did to lay out the graph is:

nodeXLControl1.Layout = new SugiyamaLayout();
nodeXLControl1.DrawGraph(true);

I guess I need to call the action that tells the graph to lay out. Right?

 

Thanks!

Peter

 

 

P.S. I would like to mention you as a supporter in my bachelor thesis. Can I get in contact with you? (The thesis is in german ;) )

May 16, 2011 at 8:18 PM
Edited May 16, 2011 at 8:19 PM

Peter:

No, you don't need to call an action to lay out the graph.  The "true" argument that you're passing to the DrawGraph() method is that method's layOutGraphFirst parameter; therefore, the DrawGraph() method will automatically lay out the graph before drawing it.  Is it not doing that?

By the way, I want to make sure that you noticed the NodeXLApi.chm help file that came with the NodeXL source code.  The help file documents all the classes, properties and methods you're using, including NodeXLControl.DrawGraph().

Thank you for offering to acknowledge us in your thesis.  There are instructions for doing so under Publications on the NodeXL Documentation tab at http://nodexl.codeplex.com/documentation.

-- Tony

May 16, 2011 at 8:42 PM

Hey Tony,

I still get the error message:

InvalidOperationException

"Microsoft.NodeXL.Visualization.Wpf.NodeXLControl.AsyncLayout: An asynchronous layout is in progress.  Check the IsLayingOutGraph property before calling this."

 

Thanks

Peter

May 16, 2011 at 11:18 PM

I don't see how a layout can be in progress if you haven't called DrawGraph() yet.  Are you running your code in a loop, or something like that?

The following code works for me.  I created a Windows Forms project, then added an ElementHost to the Form using the Designer.  Tell me how your code differs from this.

-- Tony


using System;
using System.Windows.Forms;
using Microsoft.NodeXL.Core;
using Microsoft.NodeXL.Layouts;
using Microsoft.NodeXL.Visualization.Wpf;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            NodeXLControl oNodeXLControl = new NodeXLControl();
            elementHost1.Child = oNodeXLControl;

            IGraph oGraph = oNodeXLControl.Graph;
            IVertexCollection oVertices = oGraph.Vertices;
            IEdgeCollection oEdges = oGraph.Edges;

            IVertex oVertex1 = oVertices.Add();
            IVertex oVertex2 = oVertices.Add();
            oEdges.Add(oVertex1, oVertex2);

            oNodeXLControl.Layout = new SugiyamaLayout();

            oNodeXLControl.DrawGraph(true);
        }
    }
}

May 16, 2011 at 11:22 PM

I've reread your earlier posts, and it sounds like you're trying to animate the graph to show a sequence of graph images.  Is that correct?

-- Tony

May 17, 2011 at 12:15 PM

Hey Tony,

you are right. I had a loop that started when Form1 was loaded.

I deleted the loop, now everything works fine.

 

Thanks again for you help!

Peter