.Netmap & Visual Basic 2008

Sep 3, 2008 at 12:11 AM
Edited Sep 3, 2008 at 12:41 AM
Hi,
I would like to use .NetMap for my Visual Basic application and I was able to rewrite the C# example to a working Visual Basic example. However, now I want to use it in my existing application and I am hitting a brick wall. I am sure this has to do with my amateuristic programming skills but your help is very much appreciated. The problem is the following: whenever I want to add an edge to connect two vertices I run into an Assertion Error that .NetMap throws and I don't understand why. My code is the following. 

Dim oGraph As New Graph
Public Vertex As New Vertex
Public oVertex As New VertexFactory
Public gNetworkMap As New GraphDrawer
Public oVertices As IVertexCollection
Public oEdges As IEdgeCollection

gNetworkMap.EdgeDrawer =
New PerEdgeWithLabelDrawer()
gNetworkMap.VertexDrawer =
New PerVertexWithLabelDrawer()
gNetworkMap.Graph = oGraph
oVertices = gNetworkMap.Graph.Vertices()
oEdges = gNetworkMap.Graph.Edges()

 

 

 

Vertex1 = oVertex.CreateVertex()
idVertex1 = Vertex1.ID
NetworkMapper.oVertices.Add()

 

 

 

Vertex2 = NetworkMapper.oVertex.CreateVertex()
idVertex2 = Vertex2.ID
oVertices.Add(Vertex2)
AddEdge(idVertex1, idVertex2)

Public Sub AddEdge(ByVal vertex1 As Integer, ByVal vertex2 As Integer)
oEdges.Add(oVertices(vertex1), oVertices(vertex2), True)
End Sub

The error I get is this:  Microsoft.NetMap.Core.Edge.Constructor: vertex1 argument can't be null. Parameter name: vertex1
When I change oEdges.Add(oVertices(vertex1), oVertices(vertex2), True)
to  oEdges.Add(oVertices(0), oVertices(1), True) it does  not throw the error but then the visualization won't show the vertices.

 

 

I have checked whether the vertices exists and have been added to the graph and this is the case. I have tried a lot of different things and I am sure it is reallyeasy to fix but I just don't see it. Hopefully this will provide you with enough information to answer my question.
Best regards,
Diederik

 

Sep 3, 2008 at 1:08 AM
Edited Sep 3, 2008 at 7:11 AM
Diederik:

I'm afraid I can't get your code to compile, and it's not clear to me what the code is doing.  Among other things, if "NetworkMapper" is the name of your NetMapControl instance, then it doesn't have a property or method called "oVertices".  Or is NetworkMapper something else?

In any case, the code is complicating something that is actually quite simple.  Here is the sample code translated to VB.NET, which works fine on my machine:


Imports Microsoft.NetMap.Visualization
Imports Microsoft.NetMap.Core

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Me.NetMapControl1.BeginUpdate()

        ' The default vertex drawer draws all vertices with the same
        ' color, radius, and shape.  Replace it with one that will vary
        ' the appearance of each vertex based on metadata values stored in
        ' the vertices.

        NetMapControl1.VertexDrawer = New PerVertexWithLabelDrawer()

        ' Replace the default edge drawer with one that will vary the color
        ' and width of each edge based on metadata values stored in the edges.

        NetMapControl1.EdgeDrawer = New PerEdgeWithLabelDrawer()

        ' Get the graph's vertex collection.

        Dim oVertices As IVertexCollection

        oVertices = NetMapControl1.Graph.Vertices

        ' Add three vertices.

        Dim oVertexA, oVertexB, oVertexC As IVertex

        oVertexA = oVertices.Add()
        oVertexB = oVertices.Add()
        oVertexC = oVertices.Add()

        ' Change the color, radius, and shape of vertex A.

        oVertexB.SetValue(ReservedMetadataKeys.PerColor, Color.Orange)
        oVertexB.SetValue(ReservedMetadataKeys.PerVertexRadius, 20.0F)
        oVertexB.SetValue(ReservedMetadataKeys.PerVertexShape, _
            VertexDrawer.VertexShape.Sphere)

        ' Draw vertex B as a primary label instead of a shape.  A primary
        ' label is a box containing text.

        oVertexA.SetValue(ReservedMetadataKeys.PerVertexPrimaryLabel, _
            "Primary Label")

        ' Set the primary label's text and fill colors.

        oVertexA.SetValue(ReservedMetadataKeys.PerColor, Color.White)
        oVertexA.SetValue(ReservedMetadataKeys.PerVertexPrimaryLabelFillColor, _
            Color.Black)

        ' Add a secondary label to vertex C.  A secondary label is text that
        ' is drawn outside the vertex.  It can be added to a shape, image, or
        ' primary label.

        oVertexC.SetValue(ReservedMetadataKeys.PerVertexSecondaryLabel, _
            "Secondary Label")

        ' Get the graph's edge collection.

        Dim oEdges As IEdgeCollection

        oEdges = NetMapControl1.Graph.Edges

        ' Connect the vertices with directed edges.

        Dim oEdge1, oEdge2, oEdge3 As IEdge

        oEdge1 = oEdges.Add(oVertexA, oVertexB, True)
        oEdge2 = oEdges.Add(oVertexB, oVertexC, True)
        oEdge3 = oEdges.Add(oVertexC, oVertexA, True)

        ' Customize their appearance.

        oEdge1.SetValue(ReservedMetadataKeys.PerColor, Color.Chartreuse)
        oEdge1.SetValue(ReservedMetadataKeys.PerEdgeWidth, 3)

        oEdge2.SetValue(ReservedMetadataKeys.PerEdgeWidth, 5)

        oEdge3.SetValue(ReservedMetadataKeys.PerColor, Color.ForestGreen)

        Me.NetMapControl1.EndUpdate()

    End Sub
End Class

Sep 3, 2008 at 3:27 AM
Edited Sep 3, 2008 at 7:07 AM
Diederik:

Regarding the error you reported, it's occurring because of a design bug in your AddEdge() subroutine:

Public Sub AddEdge(ByVal vertex1 As Integer, ByVal vertex2 As Integer)
    oEdges.Add(oVertices(vertex1), oVertices(vertex2), True)
End Sub

You are passing vertex IDs to the subroutine, but the oVertices(vertex1) call is looking up the vertex by index, not ID.  When a vertex with that index can't be found, "nothing" is returned, and that's what the error reported by oEdges.Add() is about.

If you really want to look up a vertex by ID, you would use the Find() method on the vertex collection.  Keep in mind that this does a linear search, so you wouldn't want to use method this if your graph is large.

The vertex collection can only be enumerated; it can't be directly indexed or efficiently searched.  Therefore, you might want to add the edges while you still have references to the edges' vertices, which is what the sample code does.

-- Tony
Sep 3, 2008 at 5:17 PM
Dear Tony, dear Tcap479,

Thank you for your replies! i got it working now but i have small new problem. I am adding vertices and edges but sometimes a vertice already exists in the oVertices collection. How can I retrieve the index of the existing vertex in the Overtices collection to use it for a new edge? I do not want to have duplicate vertices (duplicate meaning they will have the same name as given by the primarylaberpervertex option)
best regards,
Diederik
Sep 3, 2008 at 5:40 PM
Edited Sep 3, 2008 at 5:42 PM
Diederik:

I'm glad to hear of your success.

You can retrieve a vertex from the vertex collection by using the IVertexCollection.Find(name, out vertex) method.  You give it a vertex name, it searches the collection, and it tells you whether it has succeeded:

IVertex oVertex;
if (oVertices.Find("MyVertexName", out oVertex)
{
    // The vertex was found, do something with it...
}

(Pardon the C#, but my VB.NET is too rusty to type off the top of my head.)

There is also a version of Find() that searches by vertex ID rather than name.

This will work fine with small graphs.  It's inefficient with large graphs, though, because the Find() method does a linear search for the requested vertex.  Add a few thousand vertices, and those searches are going to take a while.

In the .NetMap Excel template, which needs to handle larger graphs, I create a vertex dictionary while populating the graph.  It's a Dictionary<String, IVertex>, where the key is the vertex name and the value is the vertex with that name.  When I add a vertex to the graph, I also add it to the dictionary.  Then when I'm adding edges and need to retrieve the edges' vertices, I look them up by name in the dictionary, which is very fast.  I discard the dictionary after the graph is populated.

If you're using vertex IDs instead of names, you could use a Dictionary<Int32, IVertex> instead.

Or, just use the Find() method if you're not too concerned about performance.

(I will be out of office for the rest of the week and won't be able to answer more questions until Monday.)

-- Tony
Sep 5, 2008 at 10:05 PM
Dear Tony,

I came up wiht the same solution and it works like a blaze so I am glad to hear that I am moving in the right direction.
Two other questions that I have:
1) I cannot seem to find the Microsoft.NetMap.Adapters.dll file, am I supposed to compile it myself or am I missing something? (I am would like to be able to load and save Pajek files).
2) My version of .NetMap does not recognize ReservedMetadataKeys.PerVertexPrimaryLabelFillColor, same question as with the PajekAdapter.
thank you and .NetMap is really a very nice graph library!
best,
Diederik
Sep 9, 2008 at 4:10 PM
Edited Sep 9, 2008 at 4:22 PM
Diederik:

My mistakes.  On 1), I neglected to include the Adapters DLL in the ".NetMap Class Libraries" 1.0.1.48 release.  You can build it yourself, but that's not what I intended.  On 2), version 1.0.1.48 doesn't include the ReservedMetadataKeys.PerVertexPrimaryLabelFillColor feature.

I'm working on a release right now that fixes these problems and others.  I'll post it today (9/9/2008) or tomorrow.

Thanks for pointing out these issues.

-- Tony