three for all

Tutorial

From 34allDocumentation

Jump to: navigation, search
It is the function of creative man to perceive and to connect the seemingly unconnected. William Plomer

How to write adapter for 34all?



Contents

Introduction

This tutorial is intended to help you understanding how to write network adapters for the graph visualization tool 34all. These network adapters will provide the means to connect the data you want to visualize with the 34all viewer. Rather than explaining this on a formal level it will be done by guiding you through the development of an example adapter, which hopefully captures all major questions concerning the development of 34all adapters.

Developing network adapters for 34all mainly demands of writing two classes, one for setting up 34all according to the characteristics of the data to be displayed, the other to connect 34all with the actual data. A skeleton like source code of both of these classes can be generated by using the 34all adapter wizard, which usage will be explained in the following.

Please be aware that this tutorial is not meant to be complete and will hopefully be updated regularly based on feedback from irritated users.

The network myFriends

First let us set up our example and explain which network we want to visualize. In trying to be a good example, it hopefully deals with most key points which we are trying to understand, stays as simple as possible and has no real world purpose.

Going happily with the flow of the time our goal is to visualize a social network - myFriends. The following requirements should be fulfilled by our implementation:

  • A person of the myFriends community should have the following characteristics:
    • Name
    • Age
    • Gender
    • Favorite web site
  • The gender of the person should be reflected by the frame color of the node.
  • Persons have friends within the community. Friendship is represented through a link between these two.
  • The user of this adapter should be able to specify the following parameters of the community:
    • Number of people in the community (choice among a fixed set of possibilities)
    • Minimum number of friends of a person
    • Maximum number of friends of a person
  • 34all should display by default just one person and its friends in the beginning, but the user should also be given the choice that the whole community is displayed straight away.

Good luck, that doesn't sound too complicated. Let's start the actual development of the adapter.

The wizard

In order to make the development as easy as possible and not asking developers to understand straight away how 34all wants things in particular to be, the idea of writing a wizard who hides unpleasant details was at hand. You can find this gift in the development folder of your 34all download (wizard.sh, wizard.bat). It is based on slight modification of the good made Wizard component JWizard.

The following sections will guide us through the steps of the wizard and suggest what choices to make in the case of our example network myFriends. At best you actually start the wizard and step through it while reading what is added here.


Starting the wizard

Once you started the wizard, you should see the following welcome screen. Don't pay too much attention to what is said and proceed to the next step.


Image:tut0.gif



Step 1 - Name and pool

First of all we need to give the adapter a name, specify in which subpool of the 34all's network adapter pool NAP it should reside and also find something nice for the window title. In our example lets choose

Name of the new adapter   myFriends
Pool of the new adapter misc
Window title myFriends - friends all around


Image:tut1.gif



Step 2 - Number of node attributes

The screen of Step 2 asks us to specify the number of attributes of the nodes of our network. Let's recall, the persons in our community network should have the following characteristics:

  • Name
  • Age
  • Gender
  • Favorite web site.

This would make 4 attributes, but we actually need 6 for our example. This is because:

  • None of our attributes is unique within the community – we can't exclude the case that two person have the same name (or age, favorite web site etc). Since – as it is set up at the moment – 34all needs one key attribute which value is unique among all nodes within the network, we need to add an additional attribute (which we will call ID later), that we can give an unique value.
  • We want to reflect the gender of a person by the node color. At the moment this is achieved by declaring one attribute as color attribute (Step 6) and fill it with the (hex) value the respective color. For that matter, we need one more attribute for the color.

Don't worry too much if you not get what that means – it might when we proceed. Let's choose 6 as number of attributes for our example and continue with the next step.

number of attributes   6


Image:tut2.gif


Comment 
34all's approach concerning these two additional attributes might be questionable and this example was chosen also to point to this fact. Please use the forum if you want to communicate that you are not happy with the way it is right now, I am not blown away myself. Maybe we find some more elegant solutions.



Step 3 - Names of attributes

Now we are back to easy tasks, we just need to specify the names of the attributes.

Attribute 1   name
Attribute 2 gender
Attribute 3 age
Attribute 4 url
Attribute 5 id
Attribute 6 color


Image:tut3.gif



Step 4 - Key attribute

This screen tries to explain the key attribute issue and ask for it. Good luck we already thought about it and we can choose the id attribute for it.

The value of the key attribute of the focused node is always displayed in the input field of the tool bar (for example the wikipedia title for the rikipedia adapter). Of course the user wants to know what this value is about, so we need to give a short explanation text.

In our case it is an arbitrary generated id, which value is of no value for the user. Nevertheless, 34all shows it, so lets explain it.

Key attribute: id
Key tool bar text:   id number


Image:tut4.gif


Comment 
Again, this is obviously not perfect, maybe adapter like ours shouldn't offer an input field at all. But let's discuss this in the forum, not here.



Step 5 - Title attribute

Every node has a title, the text that is displayed in the network for a node. Preferable this is also an unique value, but this is not mandatory and in our example, we will of course not use the id attribute for that, but the name of the person.

Title attribute:   name


Image:tut5.gif


Comment 
At the moment, 34all doesn't show images, but there might be an additional “image attribute” in the future, if requested by you in the forum.' The marvelous prefuse library, which is the core of the 34all framework, supports node images, so it should't be too much of a deal.

Let's continue with the next step.



Step 6 - Color attribute

We already talked about it, so let's choose the color attribute and proceed

Color attribute:   color


Image:tut6.gif



Step 7 - Url attribute

34all information displaying capacities are limited - so while 34all focuses on the network visualization, the actual information about a node might be contained in an external document, a web page for example.

In this step we can connect 34all nodes with an URL - we just have to specify the attribute which contains this URL. In our example, we choose the “url” attribute which will contain the URL of the favorite web site of the person.

URL attribute:   url


Image:tut7.gif


Please don't get impatient by now, we already made it half way through. Let's continue.



Step 8 - Tooltip

Just seeing the name of the person wouldn't be particular fancy, we actually have some more informations and want to show them. For that 34all offers a tooltip, a little window which pops up when the mouse points to a node. What is displayed can be specified here.

1   name My name
2    gender   Gender
3 age Age
4 url My favorite web site


Image:tut8.gif



Step 9 - Edge type

Edges (or links) in a network might be directed or not. In our example edges represents friendship, so let us assume that this is nothing one sided. Let's choose

Type of edges:   not directed


Image:tut9.gif



Step 10 - Number of input parameters

In most cases we want to offer the user of our adapters some influence on the network to be displayed. In our example, we will have 4 input parameters - lets choose 4 and see in the next step what they are.

Number of parameters   4


Image:tut10.gif



Step 11 - Input parameters

The last major step is now to specify these input parameters. In our example, we wanted to have the following choices made available to the user.

  • Number of people in the community (choice between 37,111,2606)
  • Minimum number of friends of a person.
  • Maximum number of friends of a person.
  • Display the whole community at once or start with an arbitrary person.

We choose the follwings settings

numNodes combobox   Size of community 37,111,2606  
minNumEdges text Minimum number of friends 4
maxNumEdges   text Maximum number of friends   12
wholeGraph checkbox Load all at once   false

We also declare the minNumEdges and maxNumEdges parameters as required input fields.


Image:tut11.gif


Comment 
Here, different types of input parameters can be specified, at the moment five (again please use the forum to communicate further needs). If the required box is checked for a parameter, an error message pops up if the field in not filled and the input dialog remains open. Further checking of the users choices can be specified if needed, looking at the ready made source code will reveal how to do that.



Step 12 - Input dialog explanation

The input dialog window is the first what the user of your adapter sees, so it might be a good idea to explain what this adapter is about and what choices can be done. Here you can specify this welcome text.

Please write whatever and proceed (feel free to use html tags).


Image:tut12.gif



Step 13 - default settings for the cache

34all caches data by default without ever deleting what is known once. This behavior can be changed in the options dialog of the adapter by the user. For many types of networks caching doesn't make sense, for example if the information is stored in a file and always available (genealogy adapter for example) Also in our example, where we generate the network on the fly, we don't want caching to happen, so let's us disable it by default.


Image:tut13.gif


Comment 
Still the user can change these settings which overrides what is specified here. It is easy to imagine cases where this user freedom shouldn't be available, but 34all doesn't allow the adapter to switch of the cache as a possibility all together at the moment.



Step 14 - Final check

Congratulations, we made it through. Let us check once more if everything is set up properly. If you want to change something, just step back to the respective step, you won't loose any data you have already specified. Once everything is set up proper, we can generate the actual source code with the next step.


Image:tut14.gif



Step 15 - Done

Finally the last screen of the wizard is reached . The skeleton like source code is generated and can be found in the subdirectory

 development/src/net/goosebumps4all/three4all/nap/misc/myFriends

In the next section, we will have a closer look at the newly generated two files Setup.java and Adapter.java .


Image:tut15.gif



The source code

The last screen of the wizard promised that we find the source code in the directory development/src/net/goosebumps4all/three4all/nap/misc/myFriends. Two files have been generated

Setup.java 
This class is responsible for setting up 34all according to the characteristics of the network we want to display. Since the wizard already got most of the necessary informations, this class is almost complete and in most cases just some minor changes have to be done.
Adapter.java 
This class connect 34all with the data. Here we have to do some more work, but all what is needed to connect to 34all is prepared.

You can find the complete source codes either in the download (with all changes already done), or you generate it yourself with the wizard or you can have a look at them here - Setup.java and Adapter.java. But most likely it would be best to talk briefly about the actual changes that have to be done, which we will do in the following.


Setup.java

As already mentioned, Setup.java is pretty much set up, we actually have just to change two lines. The blue sections in the following source code fragments are the parts to be changed, the additional black lines are just added to make it easier to find the actual part in the source code:

        /*
         * The boolean variable "loadWholeGraph" specifies, if 34all should load the complete graph
         * at startup. Meant for graphs with a limited number of nodes.
         */

    
     //-------------------------------------------------------------------------change
        loadWholeGraph       =  inputWholeGraph; 
     //-------------------------------------------------------------------------
        /*
         * The variable "firstKey" contains to value of the key of the first node to be displayed
         * by 34all. The variable has to be set by the adapter developer, otherwise 34ll will terminate.
         */
    
     //-------------------------------------------------------------------------change
        firstKey             = "0"; 
     //-------------------------------------------------------------------------

Just two changes have to be done, let us explain them.

  • We decided to give the user the choice if the whole network should be loaded at once or not. The user's decision is stored in the variable inputWholeGraph, which we use to set the configuration variable loadWholeGraph accordingly. Of course you need to look at the complete source code yourself to get the whole picture, here we just explain what needs to be changed and what these changes are about.
  • We need to tell 34all which node is the starting point of the network visualization. This information has to be stored in the variable firstKey. We choose in our example the node with the key 0 to be the number one. This of course totally depends on our data, so the firstKey variable has always to be set by the developer in the Setup.java file.

That is it, no further changes have to done in the file Setup.java. When you download the source code of the adapter you will actually find some more changes of the file Setup.java . They are done to check the users input for validity and also to tune 34all displaying characteristics a little bit. I included some comments in the download, but can also elaborate on it here if requested. Nevertheless, the essential changes are captured by the two done above, so let us better move on to the file Adapter.java and get a first version of the myFriends adapter ready.

Comment 
For the case your adapter uses 34all cache, you can set up different caches for the same adapter depending on the input parameters by using the variable cacheName .


Adapter.java

Again let us look first at the changes of the file Adapter.java that need to be done. Again the blue sections indicated the parts where we need to do some changes. You will also see some red sections, which mark parts which have to be added to the source code.

    private String inputMaxNumEdges;
    private boolean inputWholeGraph;
    
     //-------------------------------------------------------------------------new
    private Community community;
     //--------------------------------------------------------------------------
    public Adapter(T4AllSetup setup,T4AllInputParameterManager inputParameterManager) {

        inputNumNodes = inputParameterManager.get("numNodes");
        inputMinNumEdges = inputParameterManager.get("minNumEdges");
        inputMaxNumEdges = inputParameterManager.get("maxNumEdges");
        inputWholeGraph = inputParameterManager.getAsBoolean("wholeGraph");
        
        //-------------------------------------------------------------------------new
        community = new Community(inputNumNodes,inputMinNumEdges,inputMaxNumEdges);

        //----------------------------------------------------------------------------
    }

     ...

    public T4AllNodeNeighbourhood getNeighbours(T4AllNodeKey key) {

        String keyValue = key.get();
        
        T4AllNodeNeighbourhood resultNeighbourhood = new T4AllNodeNeighbourhood();
     //----------------------------------------------------------------- comment or delete	
        // Filling the neighbourhood with keys of nodes which are connected with the current node
       
        //Iterator<String> iter = ;
        //while (iter.hasNext()) {
        //    resultNeighbourhood.addNodeKey(new T4AllNodeKey(iter.next()));   
        // }
     //-----------------------------------------------------------------     
     //----------------------------------------------------------------- new	
        Person centerPerson = community.getPerson(keyValue);
        if (centerPerson == null) {
            return null;
        }
        Iterator<Person> iter = community.getNewNeighbours(centerPerson); 
        
        if (iter != null) { //iter is null if the person already has enough friends (inputMaxEdges)
 	   while (iter.hasNext()) {
 	       Person aNeighbour = iter.next();
 	       T4AllNodeKey aKey = new T4AllNodeKey(aNeighbour.getId());
 	       resultNeighbourhood.addNodeKey(aKey);
 	   }
        }
     //----------------------------------------------------------------- new	
        return resultNeighbourhood;
    }

    ...
	
    public T4AllNode getNode(T4AllNodeKey key) {

        String keyValue = key.get();
		
        T4AllNode resultNode = new T4AllNode();
     //----------------------------------------------------------------- change	
        Person aPerson = community.getPerson(keyValue);        
        resultNode.setContent("name",aPerson.getName() );
        resultNode.setContent("gender",aPerson.isMale()?"Male":"Female");
        resultNode.setContent("age",String.valueOf(aPerson.getAge()));
        resultNode.setContent("url",aPerson.getUrl());
        resultNode.setContent("id",aPerson.getId());
        resultNode.setContent("color",aPerson.isMale()?"#00FF00":"#FF0000"  );
        //-----------------------------------------------------------------
        		
        return resultNode;
    }
    
    ...

    public Iterator<T4AllNodeKey> getAllKeys() {
     //----------------------------------------------------------------- new	
        Iterator<String> iter = community.getAllKeys();

	if (iter == null) {
	    return null;
	}
	
	ArrayList<T4AllNodeKey> result = new ArrayList<T4AllNodeKey>();
	
	while (iter.hasNext()) {
	    result.add(new T4AllNodeKey(iter.next()));
	}
	return result.iterator();

    //-------------------------------------------------------------------
    }
}

Not too much changes, but what are they about. First you might wander about the class Community. This class actually generates the data we want to display, but since this tutorial is about writing adapters for 34all and not about writing JAVA classes in general (good luck for you), we are not going to look at it at all. You can find a download link for it below (or have a look at it here: Community.java). Everything which concerns 34all can be found in the Adapter class, so let us focus on what has to be done here.

First we define a community class object and give it the respective information from the user input (like size of the community, number of friends etc) Nothing special about that.

Next we come to heart of the Adapter class and what has to be understood. The Adapter class has two essential methods which have to be fleshed out by us.

public T4AllNodeNeighbourhood getNeighbours(T4AllNodeKey) 
This method gets a key as input and has to return the neighbourhood of the node of that key (called center node in the following). The neighbourhood consists of all nodes of the network which are connected with the respective center node.
public T4AllNode getNode(T4AllNodeKey) 
This method gets a key as input parameter and has to return the node represented through this key.

So how is this done.


public getNeighbours(T4AllNodeKey)

Neighbourhoods are represented through the class T4AllNodeNeighbourhood, which offers the method addNodeKey() to add a node to it. Actually you don't add nodes to neighbourhoods, but the keys of the nodes, which are defined through the class T4AllNodeKey.

While the method addNodeKey() of the class T4AllNodeNeighbourhood is used if the network has not directed edges, we use the methods addAsSourceNodeKey() and addAsTargetNodeKey() in the case of directed edges. A source node is defined as a node which points to another node, a target node is pointed to by another node. If the edge is bidirectional, meaning that both nodes point to each other, the method addAsSourceAndTargetNode(T4AllNodeKey) does the job.

I hope the approach gets clear by looking at the actual source code. For the case of directed networks, please check the source code of the genealogy adapter.

What is also important to know is that these two methods are only called once for an specific key. So there is no need to do any caching in the Adapter class. One side effect of this is that 34all can't display dynamic networks in a dynamic way, it doesn't react on changes since it doesn't ask the adapter twice with the same key. I wonder if something more flexible would be needed here.


public T4AllNode getNode(T4AllNodeKey)

This method returns a node of the network based on its key. A node is represented through the class T4AllNode. This class offers the method setContent(String,String) to set the attribute contents of the node. It takes as first argument the name of attribute (as defined while stepping through the wizard) and as second the value to be given. Since the line to be added here are quite simple, the source code is hopefully enough to understand what has to be done.


public Iterator<T4AllNodeKey> getAllKeys()

There is one additional method which we have to flesh out in the case of our example. The method getAllKeys() has to return all keys of all nodes of a network and has to be defined only if:

  • we want to display the complete network all at once
  • not all nodes are necessary connected with each other

If both is true, we need to let 34all know all keys of our network through the getAllKeys() method. In our case, we can't be sure that all persons are connected over a couple of friendships (Margret is the friend of a friend of Roger's friend Sue ...), so we need to specify it. What these keys are depends on the actual implementation of the Community class, so no need to discuss it here.


Compiling, packing, moving, enjoying

Now what is left to be done is compiling the source files, packing them into a 'jar' file, moving this into the network adapter pool and enjoying the result.

If you haven't gone through the wizard and the modifications yourself, you might want to get all source files ready made - MyFriendsSourceCode.zip .

Otherwise, if you been brave and active yourself, you first need to add the additional file Community.java to the directory development/src/net/goosebumps4all/three4all/nap/misc/myFriends. You can download it from here - Community.java .

Once the three files Setup.java, Adapter.java and Community.java are in right place, we can get our community on screen with the follwing steps.

The name [34ALLPATH] stands for the path to your 34all directory in the following.


cd [34ALLPATH]/development/src

java -classpath [34ALLPATH]/lib/34all.jar net/goosebumps4all/three4all/nap/misc/myFriends/*.java

jar -cf myFriends.jar net/goosebumps4all/three4all/nap/misc/myFriends/*.class

mv myFriends.jar [34ALLPATH]/nap/misc

[34ALLPATH]/34all.sh

If you are on a windows systems, you should of course exchange the slashes with backslashes and use the commands move and 34all.bat instead mv and 34all.sh.

If everything went well you should find the myFriends adapter in the NAP/misc menu of 34all. Emaho

Hints

  • With release 2007.05.03 34all can display node images. This new feature hasn't been described in this tutorial yet, but you can find out how to do it in the source of the ramazon adapter. Basically you have to specify the attribute which holds the image URL and have options concerning the position of the image within the node and its maximum dimension. (see Setup.java in the source of the ramazon adapter, four lines to include a node image)
  • You can find source codes of a couple of adapters in network adapter pool. The sources of them haven't been polished yet, but hopefully the sources help to get started.
  • Don't forget to switch off 34all's cache while you are developing/testing your adapter, otherwith you wouldn't get fresh results on the screen. (useCache = false;)


Conclusion

I would be happy to proclaim that it took me 10 minutes to write the myFriends adapter and that is why you should be able to write your own adapters in 7 minutes. But there are couple of reasons why this wouldn't hold true

  • It took me quite longer
  • This tutorial is obviously quite rudimentary and not overwhelmingly clear.
  • Your data demands features 34all doesn't offer
  • ...

I guess you have to go through some trial and error phases before you get your own adapter done. Every new 34all adpater I wrote so far revealed besides bugs in the framework lack of flexibilty of 34all and I am sure you will experience this as soon as you want to display some more relevant data. And that is in a way great, 34all is still in its early development stages and not meant to be complete. What is needed of course to change this situation is that you communicate what is unclear or missing, either via email or preferable in the forum. Thanks.