porting from alpha to beta
This guide provides an overview of the changes between the alpha release and the beta release and some suggestions for porting alpha applications to the new framework.
new data model
Prefuse beta has a completely revamped data model. The old graph classes are gone, replaced by the new Table, Graph, and Tree classes of the prefuse.data package. All data structures are now implemented in terms of tables, making prefuse's data management act much more like an in-memory database. The result is a much more structured and memory-efficient handling of data (though perhaps at the loss of some simplicity). Arbitratry data types, including primitive int, long, float, double, and boolean values, are supported. Graph and Tree instances now internally store data using tables for the node and edge data. This even allows the same node data table to be used for a number of different graphs simultaneously.
Tables are described using Schema objects, which denote the names, data types, and default values of data fields included in the Table and can be used to directly instantiate new Table instances.
Individual data elements are represented by the Tuple interface, which has replaced the Entity type used in the alpha version. Each Tuple is a proxy object that represents a single for of table data. Node and Edge are sub-interfaces of Tuple, additionally providing access to an underlying graph structure. Furthermore, there is no longer a TreeNode type. Instead the Node interface includes tree-specific methods. If the backing data structure is a Tree, the Node simply access that Tree. If the backing data structure is a Graph, a spanning tree is created (or a previously created spanning tree is retrieved) and accessed.
The table data structures supports many database-like features, including indexing of column data and filtering operations. Using a Predicate instance, you can issue queries to a prefuse data set, receiving an iterator over the filtered tuples. Predicates can be created by directly instantiating objects, or by parsing textual expressions written in the new prefuse expression language.
Data can be read in from formatted files using the classes of the prefuse.data.io package. Please note that the default graph file format is now GraphML, which is similar to the format used before, but is better standardized and includes strongly-typed data fields. Additionally, there is the prefuse.data.io.sql package which facilitates loading data from an SQL database. Use the ConnectionFactory class to get a DatabaseDataSource instance. You can issue SQL queries directly to the DatabaseDataSource and the results will be automatically mapped to Java data types and returned in a prefuse Table instance.
the visualization class - no more item registry
The central ItemRegistry class of the alpha version has been replaced by the Visualization class, and with this change has come a major re-working and replacement of the filtering mechanisms used in the alpha version. Like the ItemRegistry, the Visualization keeps track of all the VisualItems in the visualization as well as focus sets and all the active Displays. However, the Visualization also supports any number of data groups -- these could be tables, graphs, trees, aggregates, decorators, or other groups used for your own purposes. No longer do you have to worry about having the right filter in place just to see all your data, instead you can simply add your data directly to the visualization to create a visual abstraction of the data. You can also supply a Predicate such that only a subset of the data is mapped to a visual form. See the Javadoc API Documentation for more. There still remain a number of filter Actions which are now responsible for filtering the visual abstraction of data added to the visualization. The provided classes include a general VisibilityFilter, the FisheyeTreeFilter, and the GraphDistanceFilter (which replaces the FisheyeGraphFilter and WindowedTreeFilter of the alpha version).
visual items
VisualItems have
been revamped to support the new data model. Instead of including a reference
to a backing Entity/Tuple, the VisualItem inherits the backing data directly,
while also providing all the visual attributes (x, y, colors, size, font,
etc) from a backing table. As such, there is no longer a difference of
the getAttribute/getVizAttribute sort, simply use the get
methods of the Tuple interface.
Visual attributes can be accessed using the provided methods of the VisualItem
interface (e.g. getX()
or getSize()
) or by using
the appropriate get
method and the visual attribute's data
field name. By default all visual data field names are prefixed by an
underscore ('_') character. Thus the field names for the previous examples
would be _x
and _size
, and getDouble("_x")
and getDouble("_size")
would be equivalent method calls.
Furthermore, staring and ending values for interpolated columns have data
field names that include a :start
or :end
suffix.
Thus _x:start
is the data field name for the starting x
coordinate of an item.
In other changes, the color and fillColor attributes have been replaced with the strokeColor, fillColor, and textColor data fields, allowing you to now separately control the color of lines/shape outlines and text strings. Color values are now represented as primitive integer values encoding the red, green, blue, and alpha channels. See the ColorLib class for a number of useful methods for generating and manipulating color values.
actions and actionlists
The Action and ActionList mechanisms are still follow very much the same patterns as before, but with a few changes. First Action is now a subclass of Activity, and ActionList is a subclass of Action. This means that individual Actions can now be scheduled and run without the need for an enveloping ActionList instance. Furthermore, the Action API has been simplified such that no ItemRegistry/Visualization instance is passed in to the run method. Instead, the Actions must be registered with a specific Visualization, and will have access to that Visualization as a member variable.
In addition, you can now use the Visualization instance as a manager
for all your invokable Action instances. By registering your Action with
a Visualization, you give the Action a name and can invoke the Action
by calling the desired run
method on the Visualization instance.
This provides a convenient mechanism for managing a collection of Actions
and allowing for dynamic re-binding of the Actions by overwriting an existing
name/Action pair.
A number of new Actions have been introduced, including new layout (e.g., AxisLayout) and assignment functions (e.g., ShapeAction). ColorActions (previously named ColorFunctions) no longer set multiple color fields at once, but instead are targeted to a particular color field, such as the stroke, fill, or text colors. New assignment actions that automatically map data values to visual encodings have also been provided (i.e., DataColorAction, DataSizeAction, and DataShapeAction).
displays and control listeners
These classes remain quite similar to the alpha release versions, but with some additional features. The Display class now can also take an optional Predicate, which it uses to control which subset of the backing Visualization is painted by the Display. This can be used to create multiple Displays that show different subsets of teh data in a Visualization. The Display class also now supports damage/redraw optimizations, redrawing only the portion of the display that has changed since the last rendering operation. For largely static visualizations supporting interaction this can result in a significant performance increase. However, if desired, this optimization can be disabled. These is now also the ability to add paint listeners, that are notified both before and after painting occurs (replacing the prePaint and postPaint methods), and a listener interface for monitoring changes to the total bounds occupied by the VisualItems in the Display.
The ControlListener interface has been renamed to Control, but otherwise has changed little. Control callbacks are now thread-safe, so you should not need to use any synchronization blocks within your Control instances.
renderers and renderer factory
The Renderers still follow the same pattern, but the getBounds method has been changed to setBounds, and is now responsible for appropriately updating a bounding box stored within the VisualItem itself. Some consolidation and renaming has also occurred. The TextItemRenderer and ImageItemRenderer have been merged into the single LabelRenderer class, and DefaultEdgeRenderer is now just EdgeRenderer.
The RendererFactory API is unchanged, but the DefaultRendererFactory class has new functionalities. It supports both a default edge renderer (used as the default for EdgeItem instances) and a default item renderer (for all other VisualItem instances). In addition, you can add any number of Predicate rules which map to a particular choice of renderer.
porting guide
Porting a prefuse-alpha application to the beta framework is basically a process of taking the above changes into account.
- Load or import your data using the new prefuse data model
- Replace your ItemRegistry with a Visualization instance. Add your data to the Visualization.
- Create Actions and ActionLists as before, but now register them with the Visualization before using them. Use the Visualization itself to invoke the desired Actions. You will also need to break up your color functions such that there are individual color functions for each color field and they now return the new integer-coded color values.
- Use Displays, Controls, and Renderers as before, but update to use renamed classes where needed.
In most instances the porting is not difficult, though sometimes tedious. Using a good IDE will certainly help. Though porting can be a pain, the new framework was designed to be much more flexible, powerful, and robust than the previous version, and should increase the possibilities for your applications now and in the future.