Zonemanager

From Profusians

Jump to: navigation, search

documentation - tutorial - zone manager

Image:ZoneManagerLogo.gif
a shady attempt to forcefully trap prefuse nodes


Introduction

Zone manager is a small set of classes which provide the means to cluster nodes of force directed prefuse graphs.


The force directed layout normally structures graphs according to the connectivity of the nodes and a set of forces acting between them. Zone manager allows its user to restructure these so layout graphs by defining zone areas within the visualization, in which nodes can be placed. These zones will then form the primary structural element of the graph, the force directed layout becoming its secondary structural means.


Zone manager supports at the moment circular, rectangular and polygonal zones, for which customizable wall forces are created in order to "lock" nodes within these areas after they have been added to them. Zones can be flexible in order to adjust dynamically to the current number of nodes they contain. Possible adjustments include rescaling of zones or nodes within. Focus groups and aggregates are created and maintained for each zone, which makes handling of these "zone organized" nodes convenient.

Tutorial

This tutorial intends to give you a stepwise guide for the usage of the zone manager toolkit. This will be done by commenting on the twelve “zonedemos” coming along wit profusians download which show successive more refined usage of this toolkit. It is of course advised that you try the demos while reading this tutorial and change the zone manager related settings in order to discover the limitations of this toolkit as soon as possible.

Since polygonal zones came into being after this tutorial was written, it doesn't cover them. See the polygonal zone chapter of the zone manager documentation for an introduction of this further zone type.

Thanks to tweet's feedback there is a discussion about the the high CPU usage of zonemanager in the forum. Please check this discussion for a provisional solution and help with your feedback to improve on that.


ZoneDemo01 – no zones yet

ZoneDemo01, a cut down of Jeff's AggregateDemo from the prefuse demos, constitutes the zoneless base for the further zonedemos. No zones yet, the nodes seem to be still free and happy.

ZoneDemo02 – our first four zones

With ZoneDemo02 onwards we will restrict the freedom of the nodes by defining four zones and placing nodes into them.

There are basically five steps necessary in order to set up zone manager

  1. Specifying the zones.
  2. Creating the zones and adding them to zone manager.
  3. Adding nodes to these zones.
  4. Adding the wall forces belonging to these zones to the ForceDirectedLayout.
  5. Adding a ZoneGuardAction to the relevant (layout) action list(s)

1. Zone specification

Zones are specified by various parameters, which are organized into three classes.

  • ZoneShape - specifying the shape, size and position of the zone
  • ZoneColors - specifying the colors associated with the zone
  • ZoneAttributes - specifying further attributes of the zone like name, flexibility etc

Here we will only specify the parameters related to the ZoneShape class, which are required, and will learn later about the details of the the remaining optional parameters.

ZoneShape[] zoneShapes = new ZoneShape[4];

zoneShapes[0] = new RectangularZoneShape(-100,100,110,90);
zoneShapes[1] = new RectangularZoneShape(100,-100,120,120);
zoneShapes[2] = new CircularZoneShape(-100,-100,60);
zoneShapes[3] = new CircularZoneShape(100,100,50);

These lines specify the shape, size and position of two rectangular and two circular zones. The first two parameters specify

  • the x and y position of the center of the zone,

the remaining one(s) are

  • the radius in the case of circular zones.
  • the width and height in the case of rectangular zones.

2. Creating the zones and adding them to zone manager

These so specified zones can now be created and added to zone manager. This can be done through the createAndAddZone() method of the central API class ZoneManager.

    private void initZoneManager() {
	
	ZoneShape[] zoneShapes = new ZoneShape[4];

	zoneShapes[0] = new RectangularZoneShape(-100,100,110,90);
	zoneShapes[1] = new RectangularZoneShape(100,-100,120,120);
	zoneShapes[2] = new CircularZoneShape(-100,-100,60);
	zoneShapes[3] = new CircularZoneShape(100,100,50);


	ForceSimulator fsim = getForceSimulator(); 

	zoneManager = new ZoneManager(m_vis,fsim);

	zoneNumbers = new int[zoneShapes.length];

	for (int i=0;i<zoneShapes.length;i++) {
	    zoneNumbers[i] = zoneManager.createAndAddZone(zoneShapes[i]);    
	}

    }

Each zone managed by zone manager has an unique name and an unique number, which both can be used to refer to this zone later. Since we didn't specify a name for each zone, we just remember the respective numbers of the zones which are returned by the createAndAddZone() method for later reference.

Zone borders are realized by wallforces acting through the ForceDirectedLayout. Zonemanager automatically adds the respective wallforces of each zone managed by it to the force simulator given to its constructor. We will use this ForceSimulator later for the initialization of the ForceDirectedLayout. Here we don't use the default force simulator, but a customized one. The usage of customized nbody, drag and spring forces for the ForceSimulator is necessary to loosen the influence of these forces on the nodes. Too strong forces will in most cases succeed to pull nodes out of the zones they belong to. Please play around with these parameters as set in the getForceSimulator() method to see the implications.

3. Adding nodes to the zones

After we have defined these four zones we can add nodes to them.

 private void addNodesToZones() {

	Iterator nodeItems = m_vis.items(NODES);

	int numberOfZones = zoneManager.getNumberOfZones();

	while (nodeItems.hasNext()) {

	    NodeItem aNodeItem = (NodeItem) nodeItems.next();	    

	    int choice = (int) (Math.random() * numberOfZones);	    

	    zoneManager.addItemToZone(aNodeItem, zoneNumbers[choice]);
	    
    }	
  }

The method addItemToZone() of the ZoneManager class does the job. Here we use the previously saved zone numbers to refer to the zones, adding nodes to each of them randomly.

4. Adding the previous defined ForceSimulator to the ForceDirectedLayout

We already have defined a ForceSimulator which contains the wall forces of our zones. Now we use this simulator to initialize the ForceDirectedLayout:

ForceDirectedLayout fdl = new ForceDirectedLayout(GRAPH,zoneManager.getForceSimulator(),false);

5. Adding a ZoneGuardAction to the relevant (layout) action lists

There is one more important necessary step to set up zonemanager which needs some explanations. In order for zonemanager to work properly we need to add a ZoneGuardAction to the relevant action list.

	ActionList layout = new ActionList(Activity.INFINITY);
	layout.add(colors);

	layout.add(new ZoneGuardAction(zoneManager));

	layout.add(fdl);
	layout.add(new RepaintAction());


The ZoneGuardAction triggers an important control mechanism, which checks if all nodes are “staying” within their respective zone areas. As mentioned before, zones are realized by wall forces. These wall forces do not ensure that nodes don't jump over then. If zones are very crowded or if the spring forces are too strong, it might happen that a node escapes from its zone. The above added ZoneGuardAction will take care of this naughty ones and bring them gently back to their zone. For some partly obscured reason it seems to be necessary to include the ZoneGuardAction before the ForceDirectedLayout into the layout action list. Being to lazy right now to investigate into that in depth we just declare this as a general rule.


One more additional step

Since this demo doesn't include colors for zones and the relevant steps to draw zones, we add a special PaintListener to the display which is responsible for the drawing of the zone borders.

	addPaintListener(new ZoneBorderDrawing(zoneManager));

This paint listener is mainly meant for the early stage of the development of a zoned graph in order to be able to adjust the zone shape according to the needs. With the next demo we will introduce zone colors and the drawing of zones, which makes the use of the ZoneBorderDrawing paint listener redundant .


Done

Congratulation, we have our first zoned prefuse graph together. It is still very basic but fulfills already the primary task of zonemanager. Don't miss to drag nodes out of their zones in order to see how zonemanager pulls them back into their zone area.

ZoneDemo03 - Getting colorful

This demo will introduce colors to zones. This is achieved through the usage of the class ZoneColors:

    private void initZoneManager() {

	...
	
	ZoneColors[] zoneColors = new ZoneColors[4];
	
	zoneColors[0] = new ZoneColors(ColorLib.rgb(200, 0, 0),ColorLib.rgba(200, 0, 0,111));
	zoneColors[1] = new ZoneColors(ColorLib.rgb(0,100,200),ColorLib.rgba(0,100,200,111));
	zoneColors[2] = new ZoneColors(ColorLib.rgb(100,0,100),ColorLib.rgba(100,0,100,111));
	zoneColors[3] = new ZoneColors(ColorLib.rgb(0,200,0),ColorLib.rgba(0,200,0,111));

	ForceSimulator fsim = getForceSimulator(); 

	zoneManager = new ZoneManager(m_vis,fsim);

	zoneNumbers = new int[zoneShapes.length];

	for (int i=0;i<zoneShapes.length;i++) {
	    zoneNumbers[i] = zoneManager.createAndAddZone(zoneShapes[i],zoneColors[i]);    
	}


	zoneManager.setDrawBorderFlag(false);

    }

At the moment only two colors can be associated with a zone, a color for the zone itself and a color for the items it contains. Once zone manager becomes world famous, further colors like for the border etc might be introduced.

Next we need to add a zone renderer to the DefaultRenderFactory used by this program. This is necessary to enable the drawing of the zones, which are realized as prefuse aggregates. It is achieved through the addZoneRenderer() method of the ZoneManager class

Renderer nodeR = new ShapeRenderer(20);

DefaultRendererFactory drf = new DefaultRendererFactory();
drf.setDefaultRenderer(nodeR);

zoneManager.addZoneRenderer(drf);


In order to get the nodes and the zones colorful we need to add two color mapping rules to the respective color actions.

For the items within the zones this is done through the addZoneItemColorMapping() method:

ColorAction nFill = new ColorAction(NODES, VisualItem.FILLCOLOR);
nFill.setDefaultColor(ColorLib.gray(255));
nFill.add("_hover", ColorLib.gray(200));

zoneManager.addZoneItemColorMapping(nFill);


For the zones itself the method getZoneColorAction() can be used to get the required ColorAction.

ColorAction aFill = zoneManager.getZoneColorAction();


These two ColorAction have then of course be added to the proper actions within the program.


Wonderful, our zones and items are no longer white and boring. Before you continue you might want to check out how it looks like if you only apply one of the two color mappings, either for the zones or for the items within.

ZoneDemo04 - Reading zones from a file

So far we specified the zones within the program. As an alternative, they can also be defined in a xml file and red by ZoneManager.

private void initZoneManager() {

       ForceSimulator fsim = getForceSimulator();

	zoneManager = new ZoneManager(m_vis,fsim);

	zoneManager.addZonesFromFile("zones04.xml");

	zoneManager.setDrawBorderFlag(false);

    }


The zones04.xml is defined as follows


<zonexml>

<!-- circular zones-->
<zone shape = "circular" shapedata="-100,-100,60" itemColor="200,0,0" fillColor="200,0,0,111" name="red zone" ></zone>
<zone shape = "circular"  shapedata="100,100,50"  itemColor="0,100,200" fillColor="0,100,200,111" name="blue zone"></zone>

<!-- rectangular zones-->
<zone shape="rectangular" shapedata="100,-100,120,120" itemColor="0,200,0" fillColor="0,200,0,111" name="green zone"></zone>
<zone shape="rectangular" shapedata="-100,100,110,90"  itemColor="100,0,100" fillColor="100,0,100,111" name="purple zone"></zone>

</zonexml>


This xml file defines exactly the same zones as in our previous demo, its structure is hopefully quite straight forward. The only difference here is that we specify a name for each zone (which have to be unique ones among them). Our simple demo doesn't need these names, but later on we will learn how to use them to refer to the respective zones. The zonexml format just uses tag attributes rather than individual tags for the different parameter of a zone. While this looks less sexy in the first place it seems to be much more handy for the maintainability of the zonexml file due to its one line per zone character.


Let us now see how zones can react on the number of items they contain.

ZoneDemo05 – Let's get flexible

Zones can be defined to be flexible. This is achieved in the zone xml file by adding the attribute type="flexible" to a zone tag. In the zone05.xml file which is used by this demo three zones are defined as being flexible, only the blue zone stays inflexible.

<zonexml>

<!-- circular zones-->
<zone shape = "circular" type="flexible" name="red zone" shapedata="-100,-100,20" itemColor="200,0,0" fillColor="200,0,0,111"></zone>
<zone shape = "circular" type="inflexible" name="blue zone" shapedata="100,100,50" itemColor="0,100,200" fillColor="0,100,200,111"></zone>

<!-- rectangular zones-->
<zone shape="rectangular" type="flexible" name="green zone" shapedata="100,-100,40,40" itemColor="0,200,0" fillColor="0,200,0,111"></zone>
<zone shape="rectangular" type="flexible" name="purple zone" shapedata="-100,100,20,60" itemColor="100,0,100" fillColor="100,0,100,111"></zone>

</zonexml>


By default the size values (radius or width,height) of a flexible zone are interpreted to specify the desired size for the zone if it contains only one item. For two items the size of the zone area will be doubled and so on, keeping the "area per zone item size" factor constant. The center of flexible zones will by default stay fixed, regardless of how many nodes are within the zone.

We will see later how this default behavior of flexible zones can be customized by using subclasses of rectangular and circular zones.


Flexible zones change their size according to the number of items they contain. Whenever we add or remove items from a zone, we have to manually trigger the recalculation of these flexible zones. This is done through the recalculateFlexibility() method of the ZoneManager class, which recalculates the size of all flexible zones managed by the ZoneManager instance.

addNodesToZones();
	
zoneManager.recalculateFlexibility();


The force simulator for these flexible zones is created in quite the same manner as before, with one important difference. Rather than using the ForceSimulator class from the prefuse library we have to us the ForceSimulatorRemovableForces class from the profusians library. This new class is an extension of the original ForceSimulator which allows forces to be removed from it dynamically. This is necessary since flexible zones are able to change their size, and for that the wall forces belonging to them have to be removable from the simulator.

Flexible zones are besides this not dealt with differently then inflexible zones. The only additional step we have to do here is to add a special zone layout to the main layout routine, which takes care that the flexible zones are drawn correctly.

layout.add(zoneManager.getZoneLayout());

Great, despite many confusing words in this chapter only a few changes had to applied to the demo to get some of our zones flexible.


Now, instead of restarting this program again and again to get to see the flexibility of the zones we better move on to the next demo, in which nodes are changing their flexible zones periodically. Its time for showtime!

ZoneDemo06 - Showtime

This demo illustrates how to handle restless nodes, nodes which move from one zone to another periodically. There are basically three steps in order to achieve a rearrangement of nodes to different zones.

  1. Stopping all running layout actions.
  2. Adding nodes to their new zones. By adding a node to a new zone it is automatically removed from its former zone if any. This implies that nodes can only belong to one zone, which is a limitation of zonemanager at the moment.
  3. Recalculating all flexible zones.
  4. Starting the respective layout action again. Please notice that this layout action should contain the zoneManager.getZoneLayout() layout if you are drawing the zones.


These three steps can be found in the method shuffleZones() of this demo.


You might have noticed in the demo applets of the gallery that the changes of flexible zones are animated, a new feature of zone manager. The ZoneAggregateLayout, which is returned by the getZoneLayout() method of the zone manager class is responsible for this animation. This animation feature is by default not activated, but can be activated either through the ZoneAggregateLayout object itself or more convenient by calling the getZoneLayout() method with a true argument.

catchThem.add(zoneManager.getZoneLayout(true));

Don't miss to remove this additional argument to find out what you like more.


There is nothing zone manager related new in ZoneDemo06 apart from that, so lean back and enjoy the show for a while.

ZoneDemo07 - Special Flexible Zones

So far our flexible zones have been acting in a very regular manner – they never changed their center and expanded uniformly in all directions. We will see in the following how to implement flexible zones with more specific behavior. For that matter we will change the behavior of the purple zone in the lower left corner. Our goal is that:

  • the left border of the purple is always exactly below the center of the upper left circular red zone.
  • the purple zone expands according to the number of node items belonging to it to the right side only while its height is fixed regardless of the number of items within the zone.


In order to achieve this we need to write two classes, one subclass of the RectangularZone class and a ZoneFactory making use of this new zone.


There are basically four methods of the RectangularZone class which can be overwritten in order to change the flexible behavior of a rectangular zone. These four are:

public int getXUpdate() {
	return getInitialCenterX();
}
    
public int getYUpdate() {
	return getInitialCenterY();
}
    
public int getWidthUpdate() {
	return Math.round((float) (getInitialWidth() * Math.sqrt(getNumberOfItems())));
}
    
public int getHeightUpdate() {
	return Math.round((float) (getInitialHeight() * Math.sqrt(getNumberOfItems())));
}


These methods are always called when flexible zones are recalculated. The getInitial... methods return the respective values which were given when the zone was added to zone manager. As we saw before, by default flexible zones keep their initial specified center and expand uniformly around it, which is exactly what the above listed methods achieve.

By overriding these four methods we can change this default behavior accordingly. Let's see how this is done in our demo to achieve the desired result


public class ZoneDemo07_SpecialFlexiblePurpleZone extends RectangularZone{
    
    public ZoneDemo07_SpecialFlexiblePurpleZone(Visualization vis,ForceSimulator fsim,ZoneShape zShape, ZoneColors zColors, ZoneAttributes zAttributes)  {
	super(vis,fsim,zShape,zColors,zAttributes);
    }
    
    public float getUpdateCenterX() {
	return getInitialCenterX() + getInitialWidth() * getNumberOfItems() / 2;
    }
        
    public int getUpdateWidth() {
	return getInitialWidth() * getNumberOfItems();
    }
    
    public int getUpdateHeight() {
	return getInitialHeight();
    }
        
}


The y position of the center and the height of the zone are staying the same independent of the number of items, while the x position of the center moves to the right and the width expands accordingly.

(In this demo we are changing the behavior of a flexible rectangular zone. For the case of a flexible circular zone we would have to override the method getRadiusUpdate() instead of the getWidthUpdate() and getHeightUpdate() method of a rectangular zone.)


Now we have our special flexible zone, but how do we integrate it into zone manager?

Zone manager makes internal use of a DefaultZoneFactory in order to create zones. This zone factory can be changed by the user in order to integrate new zone types. Let's first see how this new zone factory looks like in our example.


public class ZoneDemo07_ZoneFactory extends DefaultZoneFactory{

    public ZoneDemo07_ZoneFactory() {
    }

    public Zone getZone(ZoneShape zShape,ZoneColors zColors,ZoneAttributes zAttributes) {

	if (zAttributes.getZoneName().compareTo("purple zone") == 0) {

	    return new ZoneDemo07_SpecialFlexiblePurpleZone(m_vis,m_fsim,zShape,zColors,zAttributes);

	} else
	    return super.getZone(zShape,zColors,zAttributes);

    }

}

Here we use the name of the purple zone in order to create the newly written zone for the purple zone. For all other zones we just call the getZone() method of the super class DefaultZoneFactory.


What is left is to tell zone manager to use our new zone factory instead of the default zone factory.

zoneManager.setZoneFactory(new ZoneDemo07_ZoneFactory());


While this demo introduces some more complicated implementations which have to be swallowed at first it also opens the door for a huge variety of applications being realized accordingly.

ZoneDemo08 - more refined flexible zone adjustments

So far we have seen how to make our zones flexible and how we can change the individual behavior of this flexible zones. As you might have noticed if you have watched the last demo long enough or looked carefully at the demo picture is that the purple zone sometimes overlaps with the inflexible blue zone if it contains enough nodes. What would be needed here would be a blue zone which changes its position according to the size of the purple zone. More generally speaking, we need a flexible zone which does not only react on the number of items it contains but also on the actual size and position of another zone. With ZoneDemo08 we will see how flexible zones loose their independent status.


While the purple zone remains as it is let us see how we implement this new flexible blue zone.

public class ZoneDemo08_SpecialFlexibleBlueZone extends CircularZone{

	ZoneManager m_zoneManager;
	RectangularZone neighborZone;

	public ZoneDemo08_SpecialFlexibleBlueZone(ZoneManager zManager,Visualization vis,ForceSimulator fsim,ZoneShape zShape, ZoneColors zColors, ZoneAttributes zAttributes) {
		super(vis,fsim,zShape,zColors,zAttributes);
		m_zoneManager = zManager;
	}

	public float getUpdateCenterX() {
		if (neighborZone == null) {
			neighborZone = (RectangularZone) m_zoneManager.getZone("purple zone");
		}
		return neighborZone.getUpdateCenterX()+neighborZone.getUpdateWidth()/2+getUpdateRadius()+1;
	}
}


In order to get to know the width update of the purple zone we need to use the zoneManager instance handling our zones. Here we add it as an argument to the constructor of the blue zone. We have through it access to the purple zone by using the getZone(String zoneName) method of the ZoneManager class.

Once we have the zone, we just call the respective methods of the purple zone to get required update information. Please notice that we can't call the getZone() method already in the constructor of the blue zone since we cannot assure in general in which order the zones are initiated.


This demo introduced one of the properly most tricky aspect of zone manager, the update of dependent flexible zones. (Please be careful not create a live look by creating two mutually dependent zones)

The next demo will now show how to remove nodes from zones altogether after they have been added to one.

ZoneDemo09 - Free your nodes occasionally

With this demo we go back to more easy stuff. All we want to accomplish here is that nodes are set free occasionally, should mean that sometimes all nodes are removed from their zones.

Below the crucial lines of code where we remove all node items from their zones.

 public void freeRound() {
	m_vis.cancel("freeThem");
	m_vis.cancel("keepThem");

	zoneManager.removeAllItems();
	zoneManager.setAllZonesVisible(false);

	m_vis.run("freeThem");

    }


In order to go back to the zoned world, we apply the following

    public void zoneRound() {

	m_vis.cancel("keepThem");
	m_vis.cancel("freeThem");

	zoneManager.setAllZonesVisible(true);

	shuffleZones();

	zoneManager.updateFlexibility();

	m_vis.run("catchThem");

    }


Here zonemanager doesn't accord with prefuse style in one regard. In prefuse an invisble item is automatically inactive. In difference to that the setAllZonesVisible(false) methods just has the effect that the zones are not drawn any more on the display, the zone related wall forces are still part of the initial ForceSimulator. The above lines still work since the freeThem ActionList uses a different ForceDirectedLayout which doesn't contain the zone wall forces. In most cases this would be the way to go since the usage of zones requires normally a customized ForceSimulator not very applicable for the normal zoneless ForceDirectedLayout.


Please notice that we also remove all items form their zones so that the color action doesn't paint the node items according to the zone colors. As an alternative we could also use a different color action for the free round.


So back to the initial remark, why does zonemanager idea of (in)visibility doesn't also include (in)activity. The reason for that is that invisible active zones make much sense and will be maybe even the normal way of using zones. If you want to to set all zones explicitly inactive, you can use the following method

zoneManager.setAllZonesActive(false);


The ZoneDemo09_modification1 demo shows how this works if only one ForceSimulator is used for zone and zoneless times, basically we just call both method after each other.

zoneManager.setAllZonesVisible(false);
zoneManager.setAllZonesActive(false);


Enough about flexible nodes, let's go on to something not too difficult to set up and properly quite useful for many applications, flexible zone node items.

ZoneDemo10 - Flexible node items

Flexible zones are quite helpful to react on a varying number of nodes within a zone but might not be the solution for some applications. Let's for example imagine that we want to visualize the network of prefusians around the world and on demand place all these beings in their countries on top of a map by using zonemanager. Here the zone size would have to be fixed, we can't really make a country bigger on the map because prefuse is particular popular there. (visualizing a social network on top of a map was by the way how zonemanager came into being)

Changing the size of the node items within a zone instead of the size of the zones comes here as a reasonable solution. We just rescale the items according to the number of members within the same zone. How?

First we introduce a new attribute for zones, itemtype="flexible"

<zonexml>

<zone shape = "circular" itemtype="flexible" name="red zone" shapedata="-100,-100,60" gravConstant="-0.11f" itemColor="200,0,0" fillColor="200,0,0,111"></zone>
<zone shape = "circular" itemtype="inflexible" name="blue zone" shapedata="100,100,70" gravConstant="-0.11f" itemColor="0,100,200" fillColor="0,100,200,111"></zone>

<zone shape="rectangular" itemtype="flexible" name="green zone" shapedata="100,-100,140,140" gravConstant="-4.11f" itemColor="0,200,0" fillColor="0,200,0,111"></zone>
<zone shape="rectangular" itemtype="flexible" name="purple zone" shapedata="-100,100,120,160" gravConstant="-4.11f" itemColor="100,0,100" fillColor="100,0,100,111"></zone>

</zonexml>


All zone items of all zones except the blue zone are declared to be flexible in this zone xml file.

Second we create subclasses of the used zone classes which overrides the getUpdateItemSize() method of the class. Here we look at the example of circular zones, the subclass of the rectangular zone for flexible items is defined in similar manner.

public class ZoneDemo10_CircularZoneFlexibleItems extends CircularZone{

	public ZoneDemo10_CircularZoneFlexibleItems(Visualization vis,ForceSimulator fsim,ZoneShape zShape, ZoneColors zColors, ZoneAttributes zAttributes) {
		super(vis,fsim,zShape,zColors,zAttributes);	
	}

	public double getUpdateItemSize() {
		return Math.min(3,10./getNumberOfItems());
	}
}

Please notice that there is no default behavior for flexible items as we had it for flexible zones. Whenever you want to use flexible items you have to write your own subclasses of the used zones. (there seem to be no reasonable way to define a default behavior for flexible items - any suggestions?)


Next let's have a look of the zone factory used in this example. Basically nothing new except the introduction of the hasFlexibleItems() of the ZoneAttributes class, which indicates if the items of a zone are declared to be flexible.

public class ZoneDemo10_ZoneFactory extends DefaultZoneFactory {

	public ZoneDemo10_ZoneFactory() {
	}

	public Zone getZone(ZoneShape zShape,ZoneColors zColors,ZoneAttributes zAttributes) {

		if (zAttributes.hasFlexibleItems() == true) {

			if (zShape.getZoneType().compareTo("CIRCULAR") == 0) {
				return new ZoneDemo10_CircularZoneFlexibleItems(m_vis,m_fsim,zShape,zColors,zAttributes);
			} else   {
				return new ZoneDemo10_RectangularZoneFlexibleItems(m_vis,m_fsim,zShape,zColors,zAttributes) ;  
			}

		} else {
			return super.getZone(zShape,zColors,zAttributes);
		}
	}
}


Done, these few steps are enabling flexible items. As in the case of flexible zones, the recalculation of the flexible items has to be triggered manually whenever nodes are added or removed from zones. This recalculation is also triggered through the call recalculateFlexibility() method of the ZoneManager class, which covers both types of flexibility for the sake of convenience. (If this turns out to be limitation for you please let us know in the forum).

This demo used a rescaling solution for zone items that makes nodes sometimes smaller than initially, sometimes bigger. This has been chosen for the sake of demonstration, you might normally just want to make your nodes smaller if the zone gets too crowded.

ZoneDemo11 - some nodes, some zones, sometimes

This demo shows how to put only some nodes sometimes in some zones. So far we added nodes to zones and by that implicitly removed them from their previous zone. If we just want to remove a node from its zone we can do the following

zoneManager.removeItemFromZone(aNodeItem);

PrefuseLib.setX(aNodeItem, null, -5 + (int) (10*Math.random()));
PrefuseLib.setY(aNodeItem, null, -5 + (int) (10*Math.random()));


The only thing tricky about it is that we have to put the node to a place which we know to be zonefree. Otherwise nodes who are not belonging to a zone might still be imprisoned by the the zone walls if once inside. The zone wallforces created by zonemanager act on all node items of the graph regardless if they belong to a zone or not.


ZoneDemo12 - Let's get technical

While refactoring zone manager efforts have been made to hide prefuse related technical details as much as possible in order to make it usable also for prefuse novices. Internally zone manager creates and maintains prefuse FocusGroup and Aggregates for each zone in order to realize color mappings and the drawing of zones. While these prefuse constructs doesn't have to bother user of zone manager, they can be used by more experienced prefusians for further refinements of the clustered graph.

In this demo we will show how to use the zone FocusGroups and Aggregates to react on a mouse hover events over zones and zone items.

Iterator iter = zoneManager.getZones().iterator();

while (iter.hasNext()) {
    Zone aZone = (Zone) iter.next();
    Predicate hover_and_zone =  new AndPredicate(ExpressionParser.predicate("_hover"),zoneManager.getZoneFocusGroupPredicate(aZone));
    nFill.add(hover_and_zone,ColorLib.setAlpha(aZone.getItemColor(),111));
}

The getZoneFocusGroupPredicate(Zone) method of the ZoneManager class makes the internally used and maintained zone focus group accessible for our implementation. All node items belong to a zone are part of this focus group, the above code creates color mapping rules for items which belong to a zone and are hovered by the mouse.


The drawing of the zones are realized through prefuse aggregates. In a quite similar manner than above we can implement color mapping if the mouse hovers over a zone.

zoneManager.setZoneAggregatesInteractive(true);
	
ColorAction aFill = new ColorAction(ZoneManager.ZONEAGGREGATES,VisualItem.FILLCOLOR);

Iterator iter = zoneManager.getZones().iterator();

while (iter.hasNext()) {
    Zone aZone = (Zone) iter.next();
    Predicate hover_and_zoneAggregate =  new AndPredicate(ExpressionParser.predicate("_hover"),zoneManager.getZoneAggregatePredicate(aZone));
    aFill.add(hover_and_zoneAggregate,ColorLib.setAlpha(aZone.getItemColor(),177));
}
zoneManager.addZoneColorMapping(aFill);

ZoneManager.ZONEAGGREGATES is the respective name of the aggregates group, the getZoneAggregatePredicate(Zone) method delivers the necessary predicate.

Here in the case of the zone aggregates, we also need to firstly set them interactive.

zoneManager.setZoneAggregatesInteractive(true);

By default zone aggregates are not interactive, because we don't want to allow DragControl for example to drag them around (That might be something to think about in the future but at the moment dragable zones are not implemented)

Once we make the zone aggregate construct interactive, we have to use the PredicateDragControl provided by the profusians library and exclude through it the dragging of the aggregates.

addControlListener(new PredicateDragControl(new NotPredicate(new InGroupPredicate(ZoneManager.ZONEAGGREGATES))));


In this demo we have included two hover color actions by using the zone manager internally created and maintained focus group and aggregates. Still, we don't need to worry too much about details, the respective predicates offered by zone manager give us sufficient access to these powerful prefuse constructs.


Later version of zone manager might include this two hover colors as a standard option to the ZoneColors class if requested frequently by zone manager users.

As a homework you might now want to use the zone aggregates to implement decorators for our zones, but you might also just look at the additional demo ZoneDemo12Homework to see how to get this done. We in any case leave this further demo uncommented for now and prefer to go for a beer or two.

Polygonal zones

As already mentioned before, zone manager now also includes an implementations of polygonal zones. You find three demos for this zone type in the profusians.demos.zonemanager.polygons package. These new zone type is dealt with just like circular and rectangular zones, only its shape has of course to be specified differently.

Polygons are defined through a series of connected corner points. The constructor of the PolygonalZoneShape class allows different ways of specifying the polygon, the following way is used in ZoneDemoPolygon01 demo

int[] xpoints = new int[] {-100,100,0,-100};
int[] ypoints = new int[] {0,100,-100,-200};

zoneNumber = zoneManager.createAndAddZone(new PolygonalZoneShape(xpoints,ypoints));    


For the case of defining polygonal zones in a zonexml file, the shapedata attribute is interpreted as follows. For a polygon defined through three points, (x1,y1), (x2,y2), (x3,y3), the shapedata attribute would have to be defined as follows

shapedata="x1,y1,x2,y2,x3,y3"

For our above example from ZoneDemoPolygon01 demo, it would be

shapedata="-100,0,100,100,0,-100,-100,-200"


That's all what is new about polygons, may all zone manager (user) be happy.

What's next

Writing tutorials is not an easy task and the author of this one doesn't seem to be tempted to show his mind blowing expertise concerning that yet. Please help to get these skills activated by offering your feedback about the zone manager tutorial in the forum.


The profusians.zonemanager.demos.fun package contains the source code of some further demos you might want to have a look at. You might have seen them already in the gallery. While being more playful than our dry tutorial demos they also include more smooth actions for the removing of zones. In addition

  • PrefuseHolidayCamps introduces a new renderer for zone drawing, the convex hull renderer of the AggregateDemo from the prefuse package.
  • TwoTruth shows flexible zones which don't react on the number of items they contains but disappear and appear in an animated fashion.
  • BarChartDecorator examplifies how to add further fields to the zone aggregate table and how to fill these additional fields.
  • Vulcano, well, life is anyway just a big cosmic joke isn't it?

Conclusion

Prefuse is a superb toolkit. During the implementation of zone manager it was again and again amazing to see how prefuse supports nearly all the specific needs of zone manager “graciously”.

Zone manager in opposite is just in its early development cycles and while writing demos for it it became again and again clear how much is missing. Further attempts to use zone manager will for sure bring up new demands for zone manager. Please communicate your experience with zone manager in the forum in order to help to further develop this toolkit.

Two limitations of zone manager seem to be already clear:

  • Nodes can only belong to one zone at a time.
  • When only some of the nodes are placed into zones there is the problem that the ForceDirectedLayout can't really fulfill the needs of both cases simultaneously, nodes within zones and nodes without zone limitations would ideally need different default forces to act on them.

About the first one – difficult and actually not clear how to implement this. Any suggestions?

The second, possible, just need to be done ...